C#:有效地搜索大字符串以查找其他字符串的出现

时间:2009-06-23 08:19:08

标签: c# string

我正在使用C#在大字符串中连续搜索多个字符串“关键字”,其中> = 4kb。这段代码不断循环,睡眠不会在保持合理速度的同时降低CPU使用率。 bog-down是关键字匹配方法。

我发现了一些可能性,并且它们都具有相似的效率。

1)http://tomasp.net/articles/ahocorasick.aspx - 我没有足够的关键字来成为最有效的算法。

2)正则表达式。使用实例级别,编译正则表达式。 - 提供比我要求更多的功能,效率不够。

3)String.IndexOf。 - 我需要做一个“智能”版本,因为它提供了足够的效率。循环遍历每个关键字并调用IndexOf不会削减它。

有没有人知道我可以用来实现目标的任何算法或方法?

5 个答案:

答案 0 :(得分:3)

我没试过,但你看过Rabin-Karp了吗?显然它具有糟糕的最坏情况复杂性,但通常非常好。

您的关键字是什么样的?特别是,它们总是被空格(或类似的东西)界定吗?如果是这样,你可以在查找“单词”后查看字符串,然后创建从单词到该单词索引列表的映射,或者只对你感兴趣的关键字进行映射。

如果您可以提供更多有关确切情况的详细信息(例如关键字,分隔符以及搜索结果所需的内容),那将会有所帮助。

答案 1 :(得分:3)

您是否一直在寻找相同的关键字? 试试Boyer-Moore。它需要对关键字进行一些预处理,但之后会加快速度。

答案 2 :(得分:2)

我为这个问题开发了IndexOf的有效使用:

A better way to replace many strings - obfuscation in C#

它使用关键字列表及其在字符串中的下一个位置。这样,您只需为每个关键字调用一次IndexOf,然后为您找到的每个匹配调用一次。替换大字符串中的关键字时效率特别高,因为您可以从头到尾处理字符串,而不是为每个关键字处理整个字符串一次。我不知道你为什么要在字符串中查找关键字以及你对字符串做什么,但也许它可能对你的情况有用。

答案 3 :(得分:2)

其实我以前必须解决这个问题,这很有趣。我有20k个html页面,每个页面都有一个标题,并希望其他页面上所有其他标题都链接到带有该标题的页面。听起来与你想要完成的事情非常相似。

方法:

  1. 通过将文件文本转换为{Word,Whitespace}的链接列表来处理文件的文本,其中Word被识别为带有一些特殊字符的连续字母数字序列,并且空白是导致文件的所有内容。下一个字。
  2. 对于我想要链接到的页面的每个“标题”,重复步骤1中的过程。
  3. 然后将步骤1中链接列表中节点的每个单词添加到二进制排序列表中。
  4. 现在你只需要从第2步中的每个标题链表中找到第一个单词并从第3步中搜索二进制排序列表。当单词是复数时,你可能会发现几个命中甚至是软命中,所以你可能会从您需要测试的二进制列表中有几个起始节点。
  5. 将文档处理为步骤1中描述的格式后,通过插入新节点和/或修改空白值实际上很容易修改。完成后,您只需遍历整个列表并将其全部转储到流中。
  6. 听起来比实际情况复杂,需要两天时间才能让它运转良好。

    然而,你解决它,玩得开心:)

答案 4 :(得分:0)

我刚刚在类似的帖子上发布了这个帖子,但这里可能更相关。

我正在进行类似的搜索,基本上在大约45k字节的文本中寻找大约10-50字节长的关键字。我在900万个文本中搜索了大约1900个关键词,因此尽可能快地获得这个关键词也是一个类似的优先事项。

因此,我发现使用.NET 4的最快方法是并行Regex IsMatch。

以下是获得总匹配的示例 -

needles.AsParallel ( ).Sum ( l => Regex.IsMatch ( haystack , Regex.Escape ( l ) ) ? 1 : 0 );

这适用于我的场景(上图),比我的测试中的并行比较快55%,至少对于我使用的数据大小。我还想象只有在使用多核机器时才会出现速度提升。

如果有人能找到更快的方法,会有兴趣吗?