4

我需要在传入的不是很长的文本中搜索给定字符串的出现。字符串在整个会话中都是不变的,并且并不多(~10)。额外的简化是没有任何字符串包含在任何其他字符串中。

我目前正在使用与str1 | str2 | .... 这个任务的性能很重要,所以我想知道我是否可以改进它。并不是说我的编程比 boost 家伙更好,但也许专用实现比一般实现更有效。

由于字符串长时间保持不变,我可以预先构建一个数据结构,如状态转换表。

例如,如果字符串是abcx,bcycz, 并且到目前为止我已经阅读过abc,我应该处于组合状态,这意味着you're either 3 chars into string 1, 2 chars into string 2 or 1 char into string 1. 然后阅读xnext 将使我进入string 1 matched状态等,并且除了xyz将移动到初始状态之外的任何字符,我都不需要缩回b.

任何想法或参考都表示赞赏。

4

8 回答 8

6

查看Aho–Corasick 字符串匹配算法

于 2010-08-24T20:31:14.207 回答
4

看看后缀树

于 2010-08-24T19:48:43.763 回答
1

我一直在寻找答案,但似乎没有一个非常明确......并且主要归结为几个链接。

这里让我感兴趣的是你的问题的独特性,到目前为止公开的解决方案根本没有利用我们在大海捞针中同时寻找几根针的事实。

我肯定会看看 KMP / Boyer Moore,但我不会盲目地应用它们(至少如果你有时间的话),因为它们是为单针量身定制的,我非常相信我们可以利用我们有多个字符串并使用自定义状态机(或 BM 的自定义表)一次检查所有字符串这一事实。

当然,它不太可能改善大 O(Boyer Moore 对每个字符串运行 3n,因此无论如何它都是线性的),但您可能会从常数因子中获益。

于 2010-08-25T06:22:09.420 回答
1

看看这个: http: //www.boost.org/doc/libs/1_44_0/libs/regex/doc/html/boost_regex/configuration/algorithm.html

递归/非递归区别的存在是一个非常强烈的建议,即 BOOST 不一定是线性时间离散有限状态机。因此,您很有可能可以针对您的特定问题做得更好。

最好的答案很大程度上取决于你有多少干草堆和一根针的最小尺寸。如果最小的针比几个字符长,您可能会比通用的正则表达式库做得更好。

基本上所有的字符串搜索都是通过在当前位置(光标)测试匹配来工作的,如果没有找到,则再次尝试将光标向右滑动更远。

Rabin-Karp 从您正在搜索的字符串(或多个字符串)中构建一个 DFSM,以便将测试和光标运动组合在一个操作中。但是,Rabin-Karp 最初是为单针设计的,因此如果一个匹配项可能是另一个匹配项的正确前缀,则您需要支持回溯。(请记住,当您想要重用代码时。)

另一种策略是尽可能将光标向右滑动多个字符。Boyer-Moore 就是这样做的。它通常是为单针制造的。构建一个包含所有字符的表格以及它们出现在针中的最右边的位置(如果有的话)。现在,将光标定位在 len(needle)-1。表格条目将告诉您 (a) 可能找到针的光标向左偏移量,或 (b) 您可以将光标 len(needle) 向右移动更远。

当您有不止一根针时,您的桌子的构造和使用会变得更加复杂,但它仍然可能会为您节省一个数量级的探针。您仍然可能想要创建一个 DFSM,但不是调用通用搜索方法,而是调用 dos_this_DFSM_match_at_this_offset()。

另一种策略是一次测试超过 8 位。有一个垃圾邮件杀手工具可以一次查看 32 位机器字。然后它会执行一些简单的哈希码以将结果放入 12 位,然后查看表格以查看是否有命中。每个模式都有四个条目(从模式开始的偏移量为 0、1、2 和 3),然后尽管表中有数千个模式,但它们只测试主题中每个 32 位字的一个或两个线。

所以总的来说,是的,当针是恒定的时,你可以比正则表达式更快。

于 2010-08-25T10:53:34.700 回答
0

正则表达式引擎初始化预计会有一些开销,因此如果不涉及真正的正则表达式,C - memcmp() 应该可以正常工作。

如果你能说出文件大小并给出一些具体的用例,我们可以建立一个基准(我认为这很有趣)。

有趣:memcmp 探索时序差异

问候

rbo

于 2010-08-24T19:37:44.690 回答
0

永远有博耶摩尔

于 2010-08-24T19:51:45.327 回答
0

除了 Rabin-Karp-Algorithm 和 Knuth-Morris-Pratt-Algorithm,我的 Algorithm-Book 建议使用有限状态机进行字符串匹配。对于每个搜索字符串,您需要构建这样一个有限状态机。

于 2010-08-24T20:30:54.657 回答
0

在 Flex 和 Bison 工具的支持下,您可以使用非常流行的 Lex 和 Yacc 工具来做到这一点。您可以使用 Lex 获取字符串的标记。将您的预定义字符串与从 Lexer 返回的标记进行比较。找到匹配项后,执行所需的操作。有许多网站描述了 Lex 和 Yacc。一个这样的网站是http://epaperpress.com/lexandyacc/

于 2010-08-27T11:28:04.117 回答