第一节介绍过RegexNode类,它的SplitWords用来分词,大致逻辑就是遍历要分词的字符串,不断的调用自身的Parse属性指向的委托,Parse属性指向一个bool ParseFunc(string input, int index, out string output)类型的委托,其中input表示要解析的字符串,index表示其实的解析位置,返回值表示否则匹配成功,output表示匹配成功是匹配到的字符串。如果本次匹配没有匹配到输出,就把当前字符当成一个独立的匹配结果,然后扫描指针向后移动,继续遍历扫描解析。
具体代码灰常简单,如下。
public delegate bool ParseFunc(string input, int index, out string output);
public class RegexNode {
public RegexNode() {
Nodes = new List<RegexNode>();
}
public RegexNode(ParseFunc func) {
Parse = func;
Nodes = new List<RegexNode>();
}
public List<RegexNode> Nodes { get; set; }
public ParseFunc Parse { get; set; }
public Releation Releation { get; set; }
public string Text { get; set; }
public string[] SplitWords(string input) {
List<string> result = new List<string>();
int index = 0;
while (index < input.Length) {
string output = null;
if(Parse(input, index, out output))
{
index += output.Length;
result.Add(output);
}
else
{
if (index < input.Length) {
result.Add(input.Substring(index, 1));
}
index ++;
}
}
return result.ToArray();
}
}
其实把抽象模式树转换成正则解析树的代码也很简单,因为都是树与数的转换,用一个简单的递归调用对源树进行深度优先遍历就行了,遍历的过程中根据模式树中提供的信息,调用解析方法工厂ParseFuncFactory的相关方法得到该子模式的解析函数,并赋值给目标树节点的Parse属性。代码中要考虑当前节点没有子节点的情况,如果是匹配一个或多个就用OneOrMoreMaxMatch,否则用MaxMatch,如果有子节点,要考察当前节点的Releation,然后进一步确定调用ParseFuncFactory的哪个方法,代码很短,如下。
public static RegexNode GetParseNode(PatternNode rootPatt) {
RegexNode root = new RegexNode();
root.Releation = rootPatt.Releation;
root.Text = rootPatt.Text;
if (rootPatt.Nodes.Count == 0) {
if (rootPatt.OneOrMore) {
string toMatch = rootPatt.Text.TrimEnd(new[]{'*',')'});
toMatch = toMatch.TrimStart('(');
root.Parse = ParseFuncFactory.OneOrMoreMaxMatch(toMatch);
}
else {
root.Parse = ParseFuncFactory.MaxMatch(rootPatt.Text);
}
return root;
}
foreach (var pt in rootPatt.Nodes) {
var node = GetParseNode(pt);
root.Nodes.Add(node);
}
if (rootPatt.Releation == Releation.And)
{
if (rootPatt.OneOrMore) {
root.Parse = ParseFuncFactory.MatchOneOrMoreWithAnd(root.Nodes);
}
else {
root.Parse = ParseFuncFactory.MatchAnd(root.Nodes);
}
}
else if (rootPatt.Releation == Releation.Or) {
if (rootPatt.OneOrMore) {
root.Parse = ParseFuncFactory.MatchOneOrMoreWithOr(root.Nodes);
}
else {
root.Parse = ParseFuncFactory.MatchOr(root.Nodes);
}
}
return root;
}
这部分代码比较简洁,比我预想的还简单,可见高阶函数的应用确实能使某些问题的解决变得简单,应该抽空仔细看看SICP了。这部分代码应该可挑剔的地方不多吧,大家也再找找。