C# 如何为正则表达式单词词干生成公共前缀?
我有一个单词数组,需要对其执行查找并替换为正则表达式操作,有时这个数组可能有数千个单词长。我已经测试并发现,使用通用前缀对单词进行词干分析比单独搜索要快得多。也就是说,C# 如何为正则表达式单词词干生成公共前缀?,c#,regex,recursion,C#,Regex,Recursion,我有一个单词数组,需要对其执行查找并替换为正则表达式操作,有时这个数组可能有数千个单词长。我已经测试并发现,使用通用前缀对单词进行词干分析比单独搜索要快得多。也就是说,^where | why$比^wh(ere | y)$慢。显然,在这样一个简短的示例中,这并不是一个明显的区别,但在有数千个备选方案且主题字符串很长的情况下,速度要快得多 因此,我正在寻找一种自动进行词干分析的方法,例如将字符串[]{“what”、“why”、“where”、“when”、“which”}转换为wh(at | y
^where | why$
比^wh(ere | y)$
慢。显然,在这样一个简短的示例中,这并不是一个明显的区别,但在有数千个备选方案且主题字符串很长的情况下,速度要快得多
因此,我正在寻找一种自动进行词干分析的方法,例如将字符串[]{“what”、“why”、“where”、“when”、“which”}
转换为wh(at | y | e(re | n)| I(ch))
是否已经有一个公认的算法可以做到这一点?如果没有,你会怎么做?这似乎需要递归地完成,但我不太明白怎么做。我有一个我写的方法,在有限的范围内工作,但它不雅观,60行长,使用多个嵌套的foreach循环,所以它是未来维护的噩梦。我相信有更好的方法,如果有人能为我指出正确的方向,我将不胜感激……这段代码应该可以工作:
public static class StemmingUtilities
{
private class Node
{
public char? Value { get; private set; }
public Node Parent { get; private set; }
public List<Node> Children { get; private set; }
public Node(char? c, Node parent)
{
this.Value = c;
this.Parent = parent;
this.Children = new List<Node>();
}
}
public static string GetRegex(IEnumerable<string> tokens)
{
var root = new Node(null,null);
foreach (var token in tokens)
{
var current = root;
for (int i = 0; i < token.Length; i++)
{
char c = token[i];
var node = current.Children.FirstOrDefault(x => x.Value.Value == c);
if (node == null)
{
node = new Node(c,current);
current.Children.Add(node);
}
current = node;
}
}
return BuildRexp(root);
}
private static string BuildRexp(Node root)
{
string s = "";
bool addBracket = root.Children.Count > 1;
// uncomment the following line to avoid first brakets wrapping (occurring in case of multiple root's children)
// addBracket = addBracket && (root.Parent != null);
if (addBracket)
s += "(";
for(int i = 0; i < root.Children.Count; i++)
{
var child = root.Children[i];
s += child.Value;
s += BuildRexp(child);
if (i < root.Children.Count - 1)
s += "|";
}
if (addBracket)
s += ")";
return s;
}
}
编辑:要获得
reg2=“wh(y | at | e(re | n))| a(bc | pple)”
即没有第一个包装括号,只需在BuildRexp
方法中取消对标记行的注释。IIRC有一个Perl包用于此。然后你只需要把它翻译成C#…我不确定是否有这样的库,但是一种方法是将单词加载到trie中,然后根据需要遍历它来生成正则表达式。
var toStem1 = new[] { "what", "why", "where", "when", "which" };
string reg1 = StemmingUtilities.GetRegex(toStem1);
// reg1 = "wh(at|y|e(re|n)|ich)"
string[] toStem2 = new[] { "why", "abc", "what", "where", "apple", "when" };
string reg2 = StemmingUtilities.GetRegex(toStem2);
// reg2 = "(wh(y|at|e(re|n))|a(bc|pple))"