.NET字符串解析性能改进 - 可能的代码嗅觉

时间:2010-03-09 17:48:45

标签: c# .net linq

以下代码旨在获取一个字符串并删除任何一组被认为对搜索短语不重要的任意单词。

我没有编写代码,但需要将其合并到其他内容中。它有效,这很好,但我感觉不对。但是,我似乎无法理解这种方法已经创造出来考虑另一种方法。

也许我只是让它变得比它需要的更复杂,但我觉得使用不同的技术可能会更清洁,也许是使用LINQ。

我欢迎任何建议;包括我过度思考它的建议,以及现有的代码非常清晰,简洁和高效。

所以,这是代码:

private string RemoveNonEssentialWords(string phrase)
{
    //This array is being created manually for demo purposes.  In production code it's passed in from elsewhere.
    string[] nonessentials = {"left", "right", "acute", "chronic", "excessive", "extensive", 
                                    "upper", "lower", "complete", "partial", "subacute", "severe",
                                    "moderate", "total", "small", "large", "minor", "multiple", "early",
                                    "major", "bilateral", "progressive"};
    int index = -1;

    for (int i = 0; i < nonessentials.Length; i++)
    {
        index = phrase.ToLower().IndexOf(nonessentials[i]);
        while (index >= 0)
        {
            phrase = phrase.Remove(index, nonessentials[i].Length);
            phrase = phrase.Trim().Replace("  ", " ");
            index = phrase.IndexOf(nonessentials[i]);
        }
    }

    return phrase;
}

提前感谢您的帮助。

干杯,

史蒂夫

7 个答案:

答案 0 :(得分:11)

这似乎是一种从搜索短语中删除停用词的算法。

这里有一个想法:如果这实际上是用于搜索,你是否需要结果短语是原始的完美表示(所有原始空白都完好无损),但删除了停用词,或者它可以是“足够接近”,以便结果仍然有效?

一种方法是将短语标记化(使用您选择的方法 - 可以是正则表达式,我将使用简单的拆分)然后在移除停用词的情况下重新组装它。例如:

public static string RemoveStopWords(string phrase, IEnumerable<string> stop)
{
    var tokens = Tokenize(phrase);
    var filteredTokens = tokens.Where(s => !stop.Contains(s));
    return string.Join(" ", filteredTokens.ToArray());
}

public static IEnumerable<string> Tokenize(string phrase)
{
    return string.Split(phrase, ' ');
    // Or use a regex, such as:
    //    return Regex.Split(phrase, @"\W+");
}

这不会给你完全相同的结果,但我敢打赌,它足够接近,它肯定会更有效地运行。实际搜索引擎使用与此类似的方法,因为所有内容都是在单词级别而不是字符级别编制索引和搜索的。

答案 1 :(得分:5)

我猜你的代码并没有做你想做的事情。如果我是对的,“主持”将被转换为“d”。要获得一个好的解决方案,您必须更详细地指定您的要求。我可能会使用Replace或正则表达式。

答案 2 :(得分:3)

我会使用正则表达式(在函数内创建)来执行此任务。我认为它能够立即执行所有处理,而无需通过字符串进行多次传递或必须创建多个中间字符串。

private string RemoveNonEssentialWords(string phrase)
{
    return Regex.Replace(phrase, // input
                         @"\b(" + String.Join("|", nonessentials) + @")\b", // pattern
                         "", // replacement
                         RegexOptions.IgnoreCase)
           .Replace("  ", " ");
}

模式开头和结尾的\b确保匹配位于字母数字和非字母数字字符之间的边界上。换句话说,它不会与单词的一部分匹配,就像示例代码那样。

答案 3 :(得分:1)

是的,那闻起来。

我喜欢用于解析的小型状态机,它们可以在使用委托列表的方法中自包含,循环输入中的字符并通过状态函数发送每个状态函数(我已经返回下一个状态函数)在被检查的角色上。)

为了提高性能,我会在点击一个分隔字符并在列表中检查单词之后将整个单词刷出一个字符串构建器(可能会使用哈希集)

答案 4 :(得分:1)

我会创建一个删除单词的哈希表解析每个单词,如果在哈希中只删除它一次通过数组,我相信创建一个表是O(n)。

答案 5 :(得分:0)

这看起来如何?

        foreach (string nonEssent in nonessentials)
        {
            phrase.Replace(nonEssent, String.Empty);
        }
        phrase.Replace("  ", " ");

答案 6 :(得分:0)

如果你想去Regex路线,你可以这样做。如果你想要速度,那么值得一试,你可以与其他方法进行比较/对比:

首先从数组输入创建一个正则表达式。类似的东西:

var regexString = "\\b(" + string.Join("|", nonessentials) + ")\\b";

这将导致类似:

  

\ B(左|右|慢性)\ B'/ P>

然后创建一个Regex对象来执行查找/替换:

System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(regexString, System.Text.RegularExpressions.RegexOptions.IgnoreCase);

然后你可以像这样做一个替换:

string fixedPhrase = regex.Replace(phrase, "");