查找多个字符串匹配的算法

时间:2010-07-15 23:55:15

标签: algorithm string search boost

我正在寻找一种有效算法的建议,以便在大量文本中查找所有匹配项。要搜索的术语将包含在列表中,并且可以有1000多种可能性。搜索字词可以是1个或更多字。

显然,我可以通过文本对每个搜索词进行多次传递。效率不高。

我考虑过对搜索词进行排序并组合常见的子段。这样我就可以快速消除大量术语。语言是C ++,我可以使用boost。

搜索词的示例可以是财富500强公司名称列表。

想法?

6 个答案:

答案 0 :(得分:24)

不要重新发明轮子

已经深入研究了这个问题。奇怪的是,搜索一个模式/字符串的最佳算法不容易外推到多字符串匹配

“grep”系列以非常有效的方式实现多字符串搜索。如果您可以将它们用作外部程序,请执行此操作。

如果您确实需要实现该算法,我认为最快的方法是重现agrep所做的事情(agrep在多字符串匹配方面表现优异!)。 Here是源文件和可执行文件。

here你会找到一篇论文,描述所用的算法,理论背景,以及关于字符串匹配的大量信息和指针。

值得注意的是:Knuth,Boyer,Moore,Baeza-Yates和其他人都在大力研究多字符串匹配。如果你需要一个非常快速的算法,请不要犹豫站在他们宽阔的肩膀上。不要重新发明轮子。

答案 1 :(得分:12)

与单一模式的情况一样,有多种算法可用于多模式匹配,您必须找到最适合您目的的算法。论文A fast algorithm for multi-pattern searching (archived copy)对大多数文章进行了回顾,其中包括Aho-Corasick(这是Knuth-Morris-Pratt算法的多模式版本,具有线性复杂性)和Commentz-Walter(组合Boyer-Moore和Aho-Corasick),并介绍了一个新的,它使用Boyer-Moore的想法来匹配多种模式。

该论文中未提及的另一种基于散列的算法是Rabin-Karp algorithm,它具有比其他算法更大的最坏情况复杂度,但通过散列减少线性因子来补偿它。哪一个更好取决于您的用例。如果要选择最快的,可能需要实现其中的几个并在应用程序中进行比较。

答案 2 :(得分:4)

假设大量的文本是静态的英文文本,你需要匹配整个单词,你可以尝试以下(你应该真正澄清什么是'匹配',你在看什么样的文本等等问题)。

首先将整个文档预处理为TrieDAWG

Trie / Dawg具有以下属性:

给定trie / dawg和长度为K的搜索项,您可以在O(K)时间内查找与该词相关联的数据(或判断是否没有匹配)。

与trie相比,使用DAWG可以节省更多空间。试图利用这样一个事实,即许多单词将具有共同的前缀,DAWG利用公共前缀以及公共后缀属性。

在trie中,也完全保持单词的位置列表。例如,如果文本是

That is that and so it is.

that中最后一个t的节点将包含列表{1,3},is中s的节点将与列表{2,7}相关联。

现在,当您获得一个单词搜索词时,您可以轻松地使用该词来获取该词的匹配列表。

如果您获得多字搜索字词,则可以执行以下操作:

使用搜索词中的第一个单词来演奏trie。获取匹配列表并插入hashTable H1。

现在用搜索词中的第二个单词来表达。获取比赛列表。对于每个匹配位置x,检查HashTable H1中是否存在x-1。如果是这样,请将x添加到新的哈希表H2。

用第三个单词走路,获取匹配列表。对于每个匹配位置y,检查H3中是否存在y-1,如果是,则添加到新的哈希表H3。

继续这样做。

最后,您会看到搜索词组的匹配列表,其中包含词组最后一个词的位置。

您可以通过维护列表中的排序列表并进行二分查找来优化短语匹配步骤:即例如。对于H2中的每个密钥k,您在搜索项3的排序列表中二进制搜索k + 1,如果找到它则将k + 1添加到H3。

答案 3 :(得分:3)

此问题的最佳解决方案是使用suffix tree(或suffix array)。它本质上是一个字符串的所有后缀的trie。对于长度为O(N)的文字,可以在O(N)

中构建

然后,k可以最佳地回答所有m个字符串O(m + k)的出现。

后缀树也可用于有效地查找例如最长的回文,最长的共同子串,最长的重复子串等

这是分析DNA字符串时使用的典型数据结构,可能是数百万/十亿个碱基。

另见

  • Wikipedia/Suffix tree
  • 字符串,树和序列的算法:计算机科学和计算生物学(Dan Gusfield)。

答案 4 :(得分:1)

所以你有很多搜索词,想看看它们中是否有任何一个?

纯粹在算法上,您可以按字母顺序对所有可能性进行排序,使用管道将它们连接起来,并将它们用作正则表达式,如果正则表达式引擎将查看/ant|ape/并正确地短路a中的a猿“如果它没有在”蚂蚁“中找到它。如果没有,你可以做一个正则表达式的“预编译”,并将结果“压缩”到最小重叠。即在上面的情况/a(nt|pe)/等等,递归地为每个字母。

但是,执行上述操作非常类似于将所有搜索字符串放在26个树中(26个字符,如果也是数字则更多)。使用每个字符长度的一个深度级别将字符串推到树上。

如果您的搜索字词数量很大,您可以使用搜索字词进行超快速搜索“这个字匹配搜索字词列表中的任何内容”。

理论上也可以反过来 - 将文档打包到树中,然后在其上使用搜索条件 - 如果您的文档是静态的,搜索条件会发生很大变化。

取决于您需要多少优化......

答案 5 :(得分:0)

您正在寻找的搜索字词是否也可以是完整的语句?

如果它只是单词,那么我建议从所有单词构建Red-Black Tree,然后搜索树中的每个单词。

如果它可能是发送,那么它可能会变得更复杂......(?)