C# 查找文本中所有关键字的高效算法

C# 查找文本中所有关键字的高效算法,c#,.net,algorithm,full-text-search,C#,.net,Algorithm,Full Text Search,我有很多字符串,包含许多不同拼写的文本。我通过搜索关键字来标记这些字符串,如果找到关键字,我将使用该关键字的关联文本 假设搜索字符串可以包含文本“schw.”、“schwa.”和“schwarz”。我有三个关键字,都解析为文本“schwarz” 现在,我正在寻找一种有效的方法来查找所有关键字,而不必对每个关键字执行string.Contains(关键字) 样本数据: H-Fuss ahorn 15 cm/SH48cm Metall-Fuss chrom 9 cm/SH42cm Metall-Ku

我有很多字符串,包含许多不同拼写的文本。我通过搜索关键字来标记这些字符串,如果找到关键字,我将使用该关键字的关联文本

假设搜索字符串可以包含文本“schw.”、“schwa.”和“schwarz”。我有三个关键字,都解析为文本“schwarz”

现在,我正在寻找一种有效的方法来查找所有关键字,而不必对每个关键字执行string.Contains(关键字)

样本数据:

H-Fuss ahorn 15 cm/SH48cm
Metall-Fuss chrom 9 cm/SH42cm
Metall-Kufe alufbg.12 cm/SH45c
Metall-Kufe verchr.12 cm/SH45c
Metall-Zylind.aluf.12cm/SH45cm
Kufe alufarbig
Metall-Zylinder hoch alufarbig
Kunststoffgl.schw. - hoch
Kunststoffgl.schw. - Standard
Kunststoffgleiter - schwarz für Sitzhoehe 42 cm
示例关键字(键、值):

样本结果:

Holz, Ahorn
Metall, Chrom
Metall, Kufe, Aluminium
Metall, Kufe, Chrom
Metall, Zylinder, Aluminium
Kufe, Aluminium
Metall, Zylinder, Hoch, Aluminium
Gleiter, Schwarz, Hoch
Gleiter, Schwarz
Gleiter, Schwarz
这似乎很合适“

算法是字符串搜索 Alfred V.Aho发明的算法 还有玛格丽特·J·科拉西克。它是一种 字典匹配算法的实现 定位有限组的元素 字符串中的字符串(“字典”) 输入文本。它匹配所有模式 “一下子”,所以这个问题的复杂性 算法的长度是线性的 图案加上图案的长度 搜索的文本加上 输出匹配。请注意,因为所有 如果找到匹配项,则可能存在 二次匹配数,如果每个 子字符串匹配(例如字典= a、 aa、aaa、aaaa和输入字符串为 aaaa)

这是一个字符串 Michael创建的搜索算法 1987年,O.拉宾和理查德·卡普 它使用哈希来查找 文本中的一组模式字符串。对于 长度为n和p的文本 组合长度m,其平均值和 最佳运行时间为O(n+m)in 空间O(p),但最坏的情况是 O(纳米)。相比之下,Aho-Corasick 字符串匹配算法已经实现 渐近最坏时间复杂度 空间O(m)中的O(n+m)


我建议:

1) 使用
string.Split
进行标记化,并与您拥有的密钥字典进行匹配


2) 使用
ReadToken()
方法实现tokeniser,它将字符添加到缓冲区,直到找到(拆分可能就是这样)拆分字符并将其作为标记输出。然后你检查你的字典。

也许它有点过于强大,但你肯定应该看看。

如果你有一组固定的关键字,你可以使用(f)lex,或者

我会为每组关键字使用预编译的正则表达式进行匹配。在后台,它们被“编译”为有限自动机,因此它们在识别字符串中的模式方面非常快,并且比
包含的
对于每个可能的字符串都要快得多

使用:
System.Text.RegularExpressions

在您的示例中:

  • “schw.”、“schwa.”和“schwarz”
  • newregex(@“schw(a?\.\arz)”,RegexOptions.Compiled)

此处提供的进一步文档:

标记化是不可能的,因为某些可能用作分隔符的字符是关键字的一部分。即使我将字符串标记为单词,关键字仍然可以出现在单词的某个地方。您的示例没有传达这一点。确实,它们被用于单词的结尾(例如“Schw”),但不在单词的中间——除非有这样的情况,你没有共享。Aho Crasick算法看起来很有前途。我目前正在看一个实现算法的代码项目:Aho Corasick正是您想要的。我建议的另一个解决方案是使用一个regex库,它也可以构造一个DFA,比如我最近从java移植的基于re2的东西,非常高效地实现了Aho Corasick:它非常快,适合生产使用。有趣的项目,值得一看。但是,将它们集成到我当前的c#项目中看起来就像一个独立的项目:-)每个关键字(或组)匹配一个正则表达式,这并不太好。或者一个真正可怕的regexp,每个组都有交替。Aho Crasick的做法基本上与将HorrEndours regexp合并到DFA中的做法相同,但如果没有regexp的全部复杂性,则更容易实现。
Holz, Ahorn
Metall, Chrom
Metall, Kufe, Aluminium
Metall, Kufe, Chrom
Metall, Zylinder, Aluminium
Kufe, Aluminium
Metall, Zylinder, Hoch, Aluminium
Gleiter, Schwarz, Hoch
Gleiter, Schwarz
Gleiter, Schwarz