Algorithm 从较小字符串中的一组较大字符串中查找所有匹配项

Algorithm 从较小字符串中的一组较大字符串中查找所有匹配项,algorithm,text,substring,Algorithm,Text,Substring,我有一大套单词和短语(词典或字典),其中包括通配符。我需要在更小的字符串(目前大约150个字符)中找到这些单词和短语的所有实例 起初,我想反向运行操作;那就是检查我的小字符串中的每个单词是否都存在于词典中,词典可以实现为哈希表。问题是,我的词典中的一些值不是单个单词,许多值是通配符(例如substri*) 我正在考虑使用,但我不确定这是最好的选择 执行此操作的有效算法或方法是什么? 样本数据: 该词典包含数百个单词,并可能扩展。这些单词可能以通配符(星号)结尾。以下是一些随机示例: 好 坏的

我有一大套单词和短语(词典或字典),其中包括通配符。我需要在更小的字符串(目前大约150个字符)中找到这些单词和短语的所有实例

起初,我想反向运行操作;那就是检查我的小字符串中的每个单词是否都存在于词典中,词典可以实现为哈希表。问题是,我的词典中的一些值不是单个单词,许多值是通配符(例如substri*)

我正在考虑使用,但我不确定这是最好的选择

执行此操作的有效算法或方法是什么?

样本数据:

该词典包含数百个单词,并可能扩展。这些单词可能以通配符(星号)结尾。以下是一些随机示例:

  • 坏的
  • 释放*
  • 粗心的*
  • 巨大损失
我们正在分析的文本(此时)是简短的、非正式的(语法方面的)英语陈述。文本的主要例子(同样,在这个时候)是推特推特。这些限制大约为140个字符。例如:

Just got the Google nexus without a contract. Hands down its the best phone 
I've ever had and the only thing that could've followed my N900.

虽然注意到我们正在对这篇文章进行非常简单的情绪分析可能会有所帮助;我们的情绪分析技术与我无关。我只是将一个现有的解决方案迁移到一个“实时”处理系统,需要执行一些优化。

让我直说吧。您有一大组查询和一个小字符串,并且希望在该字符串中查找所有这些查询的实例


在这种情况下,我建议您疯狂地索引那个小文档,以便您的搜索时间尽可能短。地狱。有了这个文档大小,我甚至会考虑做一些小的突变(以匹配通配符等等),也会对它们进行索引。

< P>我认为这是一个很好的用例,它是专门用来在一个字符串中找到一组大串的所有匹配的。它分两个阶段运行-第一阶段创建匹配自动机(可以提前完成,只需要线性时间),第二阶段使用自动机查找所有匹配(只需要线性时间,加上与匹配总数成比例的时间)。该算法也可用于支持通配符搜索


希望这有帮助

你可能仍然会使用你最初的想法,即对照字典检查文本中的每个单词。但是,为了有效地运行它,您需要为字典编制索引,以便快速查找。信息检索系统中使用的一个技巧是存储所谓的permuterm索引

基本上,您要做的是在字典中存储单词的所有可能排列(例如,for house):

然后可以使用此索引快速检查通配符查询。例如,如果您有ho*e,您可以在permuterm索引中查找以
e$ho
开头的术语,您将很快找到与house匹配的术语


搜索本身通常采用对数搜索策略(二进制搜索或b-树),因此通常速度非常快。

我想给出的一个答案是搜索算法。这是使用的算法。Grep可能是最快的搜索工具之一。此外,您可以使用类似于让grep并行运行的方法,从而真正加快算法的速度


此外,这里还有一个您可能会感兴趣的问题。

这并不能准确回答算法问题,但请查看库。Python、Ruby和其他各种编程语言都有很好的接口。根据我的经验,它的速度非常快,在我的代码中消除了非常类似的瓶颈,几乎没有额外的代码

唯一的复杂性来自重叠模式。如果您希望模式从单词边界开始,您应该能够将字典划分为一组正则表达式
r\u 1,r\u 2,…,r\u k
,其形式为
\b(foobar | baz baz\S*|…)
,其中
r\u{i+1}
中的每个组在
r\u i
中都有前缀。然后可以短路计算,因为如果
r{i+1}
匹配,则
r_i
必须匹配


除非你用高度优化的C语言实现你的算法,否则我敢打赌,这种方法将比这个线程中其他地方的任何(算法上优越的)答案都要快。

只要模式是完整的单词:你不想
匹配
存储
;空格和标点符号是匹配锚定符,然后一个简单的方法是将词典翻译成扫描仪生成器输入(例如,您可以使用),生成扫描仪,然后在输入上运行它

扫描生成器用于识别输入中出现的令牌,其中每个令牌类型由正则表达式描述。Flex和类似的程序可以快速创建扫描仪。默认情况下,Flex最多可以处理8k规则(在您的示例中是词典条目),并且可以扩展。生成的扫描仪以线性时间运行,实际上非常快

在内部,标记正则表达式在标准的“克莱恩定理”管道中进行转换:首先转换为NFA,然后转换为DFA。然后将DFA转换为其唯一的最小形式。这是在HLL表中编码的,HLL表在通过引用该表实现扫描仪的包装器内发出。这就是flex所做的,但其他策略也是可能的。例如,可以将DFA转换为
goto
代码,其中在代码运行时,DFA状态由指令指针隐式表示

空格作为锚的原因是,像Flex这样的程序创建的扫描器通常无法使用
house$
ouse$h
use$ho
...
e$hous
%option noyywrap
%%
"good"                    { return 1; }
"bad"                     { return 2; }
"freed"[[:alpha:]]*       { return 3; }
"careless"[[:alpha:]]*    { return 4; }
"great"[[:space:]]+"loss" { return 5; }
.                         { /* match anything else except newline */ }
"\n"                      { /* match newline */ }
<<EOF>>                   { return -1; }
%%
int main(int argc, char *argv[])
{
  yyin = argc > 1 ? fopen(argv[1], "r") : stdin;
  for (;;) {
    int found = yylex();
    if (found < 0) return 0;
    printf("matched pattern %d with '%s'\n", found, yytext);
  }
}
$ flex -i foo.l
$ gcc lex.yy.c
$ ./a.out
Good men can only lose freedom to bad
matched pattern 1 with 'Good'
matched pattern 3 with 'freedom'
matched pattern 2 with 'bad'
through carelessness or apathy.
matched pattern 4 with 'carelessness'