parent
52ede9fe96
commit
8e9df3fc52
34
Katheryne.Tests/Mocks/MockParamModule.cs
Normal file
34
Katheryne.Tests/Mocks/MockParamModule.cs
Normal file
|
@ -0,0 +1,34 @@
|
|||
using Katheryne.Abstractions;
|
||||
|
||||
namespace Katheryne.Tests.Mocks;
|
||||
|
||||
public class MockParamModule : IParamsModule
|
||||
{
|
||||
private readonly Dictionary<string, Func<string>> _functions = new();
|
||||
|
||||
public string ModuleName => "test";
|
||||
|
||||
public MockParamModule()
|
||||
{
|
||||
_functions.Add("hello", Hello);
|
||||
}
|
||||
|
||||
public string this[string param]
|
||||
{
|
||||
get
|
||||
{
|
||||
Func<string> func = _functions[param];
|
||||
return func();
|
||||
}
|
||||
}
|
||||
|
||||
public bool ContainsParam(string param)
|
||||
{
|
||||
return _functions.ContainsKey(param);
|
||||
}
|
||||
|
||||
private string Hello()
|
||||
{
|
||||
return "Hello, Katheryne";
|
||||
}
|
||||
}
|
|
@ -1,14 +1,25 @@
|
|||
using System.Text.RegularExpressions;
|
||||
using Katheryne.Abstractions;
|
||||
using Katheryne.Exceptions;
|
||||
using Katheryne.Models;
|
||||
using Katheryne.Tests.Mocks;
|
||||
|
||||
namespace Katheryne.Tests;
|
||||
|
||||
public class StringFormatterTests
|
||||
{
|
||||
private readonly Dictionary<string, IParamsModule> _modules = new();
|
||||
|
||||
public StringFormatterTests()
|
||||
{
|
||||
var module = new MockParamModule();
|
||||
_modules.Add(module.ModuleName, module);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormatTest1()
|
||||
{
|
||||
StringFormatter formatter = new("Hello $1");
|
||||
StringFormatter formatter = new("Hello $1", _modules);
|
||||
|
||||
Regex regex = new("I'm (.*)");
|
||||
|
||||
|
@ -23,7 +34,7 @@ public class StringFormatterTests
|
|||
[Fact]
|
||||
public void FormatTest2()
|
||||
{
|
||||
StringFormatter formatter = new("$你好呀 $1, 欢迎你离开垃圾的$2.");
|
||||
StringFormatter formatter = new("$你好呀 $1, 欢迎你离开垃圾的$2.", _modules);
|
||||
|
||||
Regex regex = new("你好,我是(.*),我来自(.*)\\.");
|
||||
|
||||
|
@ -34,4 +45,21 @@ public class StringFormatterTests
|
|||
|
||||
Assert.Equal("$你好呀 Ichirinko, 欢迎你离开垃圾的Trinity.", formatter.Format(match.Groups));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParamFormatTest1()
|
||||
{
|
||||
StringFormatter formatter = new("Test @test/hello", _modules);
|
||||
|
||||
Regex regex = new(".*?");
|
||||
Match match = regex.Match("Test Input");
|
||||
|
||||
Assert.Equal("Test Hello, Katheryne", formatter.Format(match.Groups));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParamFormatTest2()
|
||||
{
|
||||
Assert.Throws<GrammarException>(() => new StringFormatter("Test @test/nonexistent", _modules));
|
||||
}
|
||||
}
|
13
Katheryne/Abstractions/IParamsModule.cs
Normal file
13
Katheryne/Abstractions/IParamsModule.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
namespace Katheryne.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// 参数实现模块
|
||||
/// </summary>
|
||||
public interface IParamsModule
|
||||
{
|
||||
public string ModuleName { get; }
|
||||
|
||||
public string this[string param] { get; }
|
||||
|
||||
public bool ContainsParam(string param);
|
||||
}
|
|
@ -59,14 +59,16 @@ public class KatheryneChatRobot : IChatRobot
|
|||
if (answer.IsFormat)
|
||||
{
|
||||
string temp = answer.Format(match.Groups);
|
||||
_logger.LogInformation("Format answer {} to {}.", answer.RowString, temp);
|
||||
_logger.LogInformation("Format answer {} to {}.",
|
||||
answer.RowString, temp);
|
||||
result.Add(temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Add(answer.RowString);
|
||||
}
|
||||
_logger.LogInformation("Moving to stage {} on input {}.", _currentStage, input);
|
||||
_logger.LogInformation("Moving to stage {} on input {}.",
|
||||
_currentStage, input);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +95,8 @@ public class KatheryneChatRobot : IChatRobot
|
|||
_currentStage = transformer.NextStage;
|
||||
result.Add(_grammarTree[_currentStage].Answer.RowString);
|
||||
|
||||
_logger.LogInformation("Moving to stage {} with empty transform.", _currentStage);
|
||||
_logger.LogInformation("Moving to stage {} with empty transform.",
|
||||
_currentStage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
3
Katheryne/Models/GrammarParam.cs
Normal file
3
Katheryne/Models/GrammarParam.cs
Normal file
|
@ -0,0 +1,3 @@
|
|||
namespace Katheryne.Models;
|
||||
|
||||
public record GrammarParam(string OriginString, string Module, string Param);
|
|
@ -1,3 +1,4 @@
|
|||
using Katheryne.Abstractions;
|
||||
using Katheryne.Exceptions;
|
||||
|
||||
namespace Katheryne.Models;
|
||||
|
@ -6,11 +7,11 @@ public class GrammarTree
|
|||
{
|
||||
private readonly Dictionary<string, InnerStage> _stages = new();
|
||||
|
||||
public GrammarTree(LexicalModel model)
|
||||
public GrammarTree(LexicalModel model, Dictionary<string, IParamsModule> modules)
|
||||
{
|
||||
foreach (Stage stage in model.Stages)
|
||||
{
|
||||
_stages[stage.Name] = new InnerStage(stage);
|
||||
_stages[stage.Name] = new InnerStage(stage, modules);
|
||||
}
|
||||
|
||||
if (!Validate(model))
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
using Katheryne.Abstractions;
|
||||
|
||||
namespace Katheryne.Models;
|
||||
|
||||
internal class InnerStage
|
||||
|
@ -8,10 +10,10 @@ internal class InnerStage
|
|||
|
||||
public StringFormatter Answer { get; }
|
||||
|
||||
public InnerStage(Stage stage)
|
||||
public InnerStage(Stage stage, Dictionary<string, IParamsModule> modules)
|
||||
{
|
||||
Name = stage.Name;
|
||||
Answer = new StringFormatter(stage.Answer);
|
||||
Answer = new StringFormatter(stage.Answer, modules);
|
||||
|
||||
foreach (Transformer transformer in stage.Transformers)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using System.Text.RegularExpressions;
|
||||
using Katheryne.Abstractions;
|
||||
using Katheryne.Exceptions;
|
||||
|
||||
namespace Katheryne.Models;
|
||||
|
||||
|
@ -7,12 +9,20 @@ namespace Katheryne.Models;
|
|||
/// </summary>
|
||||
public class StringFormatter
|
||||
{
|
||||
private readonly string _originString;
|
||||
private readonly List<FormatTag> _formatTags = new();
|
||||
private static readonly HashSet<char> s_delimiters = new()
|
||||
{
|
||||
',', '.', '!', ';', '?', ' ', ',', '。', ';'
|
||||
};
|
||||
|
||||
public StringFormatter(string originString)
|
||||
private readonly string _originString;
|
||||
private readonly Dictionary<string, IParamsModule> _modules;
|
||||
private readonly List<FormatTag> _formatTags = new();
|
||||
private readonly List<GrammarParam> _params = new();
|
||||
|
||||
public StringFormatter(string originString, Dictionary<string, IParamsModule> modules)
|
||||
{
|
||||
_originString = originString;
|
||||
_modules = modules;
|
||||
|
||||
GetFormatTags();
|
||||
}
|
||||
|
@ -35,22 +45,33 @@ public class StringFormatter
|
|||
result = result.Replace(tag.Value, collection[tag.Index].Value);
|
||||
}
|
||||
|
||||
foreach (GrammarParam param in _params)
|
||||
{
|
||||
result = result.Replace(param.OriginString,
|
||||
_modules[param.Module][param.Param]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void GetFormatTags()
|
||||
{
|
||||
List<int> indexes = new();
|
||||
List<int> tagIndices = new();
|
||||
List<int> paramIndices = new();
|
||||
|
||||
for (var i = 0; i < _originString.Length; i++)
|
||||
{
|
||||
if (_originString[i] == '$')
|
||||
{
|
||||
indexes.Add(i);
|
||||
tagIndices.Add(i);
|
||||
}
|
||||
else if (_originString[i] == '@')
|
||||
{
|
||||
paramIndices.Add(i);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (int index in indexes)
|
||||
foreach (int index in tagIndices)
|
||||
{
|
||||
string value = string.Empty;
|
||||
int pos = index + 1;
|
||||
|
@ -74,5 +95,43 @@ public class StringFormatter
|
|||
|
||||
_formatTags.Add(new FormatTag('$' + value, int.Parse(value)));
|
||||
}
|
||||
|
||||
List<char> chars = new();
|
||||
foreach (int index in paramIndices)
|
||||
{
|
||||
chars.Clear();
|
||||
int i = index + 1;
|
||||
|
||||
while (i < _originString.Length && !s_delimiters.Contains(_originString[i]))
|
||||
{
|
||||
chars.Add(_originString[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
string text = new(chars.ToArray());
|
||||
|
||||
string[] array = text.Split('/');
|
||||
|
||||
if (array.Length != 2)
|
||||
{
|
||||
throw new GrammarException($"Failed to parse grammar param: {text}.");
|
||||
}
|
||||
|
||||
if (!_modules.ContainsKey(array[0]))
|
||||
{
|
||||
throw new GrammarException($"Unknown module {array[0]}.");
|
||||
}
|
||||
|
||||
if (!_modules[array[0]].ContainsParam(array[1]))
|
||||
{
|
||||
throw new GrammarException($"Module {array[0]} doesn't support {array[1]}.");
|
||||
}
|
||||
|
||||
_params.Add(new GrammarParam(
|
||||
'@' + text,
|
||||
array[0],
|
||||
array[1]
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,6 +13,8 @@ public class KatheryneChatRobotFactory : IChatRobotFactory
|
|||
private readonly ILogger<KatheryneChatRobot> _robotLogger;
|
||||
private readonly DefaultChatRobot _defaultChatRobot;
|
||||
|
||||
private readonly Dictionary<string, IParamsModule> _modules = new();
|
||||
|
||||
private Grammar? _grammar;
|
||||
|
||||
public string GrammarText { get; private set; } = string.Empty;
|
||||
|
@ -48,7 +50,8 @@ public class KatheryneChatRobotFactory : IChatRobotFactory
|
|||
{
|
||||
throw new GrammarException("Failed to parse lexical model.", ex);
|
||||
}
|
||||
_grammar = new Grammar(new GrammarTree(model), model.RobotName, model.BeginStageName);
|
||||
_grammar = new Grammar(new GrammarTree(model, _modules),
|
||||
model.RobotName, model.BeginStageName);
|
||||
}
|
||||
|
||||
public IChatRobot GetRobot()
|
||||
|
|
Loading…
Reference in New Issue
Block a user