Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何为正则表达式单词词干生成公共前缀?_C#_Regex_Recursion - Fatal编程技术网

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))"