什么是最有效(读取时间)字符串搜索方法? (C#)

时间:2009-03-01 11:34:29

标签: c# algorithm string search

我发现我的程序正在搜索许多冗长的字符串(20,000+),试图找到一个特定的独特短语。

在C#中执行此操作的最有效方法是什么?

以下是目前的代码:

  1. 搜索从startPos开始,因为目标区域在某种程度上从一开始就被删除了
  2. 它循环遍历字符串,在每一步它检查该点的子字符串是否以startMatchString开头,这是指示已找到目标字符串的开头。 (目标字符串varys的长度)。
  3. 从这里创建一个新的子字符串(切掉标记目标字符串开头的11个字符)并搜索endMatchString
  4. 我已经知道这是一个非常复杂且可能非常无效的算法。 什么是实现相同结果的更好方法?

    string result = string.Empty;    
    for (int i = startPos; i <= response.Length - 1; i++)
    {
       if (response.Substring(i).StartsWith(startMatchString))
       {
           string result = response.Substring(i).Substring(11);
           for (int j = 0; j <= result.Length - 1; j++)
           {
               if (result.Substring(j).StartsWith(endMatchString))
               {
                   return result.Remove(j)
               }
           }
       }
    }
    return result;
    

8 个答案:

答案 0 :(得分:7)

有很多算法,

  • boyer和moore
  • 星期日
  • Knuth的莫里斯-普拉特
  • 拉宾-卡普

我建议使用简化的Boyer-Moore,名为Boyer-Moore-Horspool。

C代码出现在维基百科上。 对于java代码,请查看

http://www.fmi.uni-sofia.bg/fmi/logic/vboutchkova/sources/BoyerMoore_java.html

关于这些的好文章可以在下面找到 http://www.ibm.com/developerworks/java/library/j-text-searching.html

如果你想使用内置的东西去正则表达式。

答案 1 :(得分:7)

您可以使用String.IndexOf,但请确保使用StringComparison.Ordinal,否则可能会慢一个数量级。

private string Search2(int startPos, string startMatchString, string endMatchString, string response) {
    int startMarch = response.IndexOf(startMatchString, startPos, StringComparison.Ordinal);
    if (startMarch != -1) {
        startMarch += startMatchString.Length;
        int endMatch = response.IndexOf(endMatchString, startMarch, StringComparison.Ordinal);
        if (endMatch != -1) { return response.Substring(startMarch, endMatch - startMarch); }
    }
    return string.Empty;
}

在183 KB文件的大约40%处搜索1000次字符串需要大约270毫秒。没有StringComparison.Ordinal,它花了大约2000毫秒 使用您的方法搜索一次时间超过60秒,因为它在每次迭代时创建一个新字符串(O(n)),使您的方法为O(n ^ 2)。

答案 2 :(得分:6)

这取决于您在字符串中尝试查找的内容。如果您正在寻找特定序列IndexOf/Contains速度很快,但如果您正在寻找通配符模式Regex则针对此类搜索进行了优化。

答案 3 :(得分:4)

我会尝试使用正则表达式而不是滚动自己的字符串搜索算法。您可以预编译正则表达式以使其运行得更快。

答案 4 :(得分:0)

你可以使用正则表达式;它针对这种搜索和操作进行了优化。

您也可以尝试IndexOf ...

string result = string.Empty;

if (startPos >= response.Length) 
    return result;

int startingIndex = response.IndexOf(startMatchString, startPos);
int rightOfStartIndex = startingIndex + startMatchString.Length;

if (startingIndex > -1 && rightOfStartIndex < response.Length)
{
    int endingIndex = response.IndexOf(endMatchString, rightOfStartIndex);
    if (endingIndex > -1)
        result = response.Substring(rightOfStartIndex, endingIndex - rightOfStartIndex);
}

return result;

答案 5 :(得分:0)

对于非常长的字符串,你无法击败boyer-moore搜索算法。它比我在这里解释的要复杂得多,但CodeProject网站上有一篇很好的文章。

答案 6 :(得分:0)

如前所述,正则表达式是你的朋友。 您可能想查看RegularExpressions.Group。 这样,您可以命名匹配结果集的一部分。

Here is an example

答案 7 :(得分:0)

以下是使用IndexOf的示例(提防:从我的头顶写下,没有测试过):

int skip = 11;
int start = response.IndexOf(startMatchString, startPos);
if (start >= 0)
{
   int end = response.IndexOf(startMatchString, start + skip);
   if (end >= 0)
       return response.Substring(start + skip, end - start - skip);
   else
       return response.Substring(start + skip);
}
return string.Empty;