用于查找文本中所有关键字的高效算法

时间:2010-11-18 11:21:23

标签: c# .net algorithm full-text-search

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

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

现在我正在寻找一种有效的方法来查找所有关键字,而不需要为每个关键字做一个字符串.Contains(keyword)。

示例数据:

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

示例关键字(键,值):

h-fuss, Holz
ahorn, Ahorn
metall, Metall
chrom, Chrom
verchr, Chrom
alum, Aluminium
aluf, Aluminium
kufe, Kufe
zylind, Zylinder
hoch, Hoch
kunststoffgl, Gleiter
gleiter, Gleiter
schwarz, Schwarz
schw., Schwarz

示例结果:

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

5 个答案:

答案 0 :(得分:15)

这似乎符合“Algorithms using finite set of patterns

  

Aho–Corasick string matching   algorithm是一个字符串搜索   Alfred V. Aho发明的算法   和Margaret J. Corasick。这是一种   词典匹配算法   定位有限集的元素   一个字符串(“字典”)   输入文本。它匹配所有模式   “立刻”,所以复杂性   算法的长度是线性的   模式加上长度   搜索文本加上数量   输出匹配。请注意,因为所有   匹配被发现,可以有一个   如果每个匹配的二次匹配数   子串匹配(例如dictionary =   a,aa,aaa,aaaa和输入字符串是   AAAA)。

     

Rabin–Karp algorithm是一个字符串   搜索算法由Michael创建   O. Rabin和Richard M. Karp于1987年   使用散列来查找任何一个   在文本中的模式字符串集。对于   长度为n和p的图案   组合长度m,其平均值和   最佳案例运行时间为O(n + m)in   空间O(p),但最坏的情况是   O(纳米)。相比之下,Aho-Corasick   字符串匹配算法有   渐近最差时间复杂度   空间O(m)中的O(n + m)。

答案 1 :(得分:3)

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

使用:System.Text.RegularExpressions

在你的例子中:

  • “schw。”,“schwa。”和“schwarz”
  • new Regex(@"schw(a?\.|arz)", RegexOptions.Compiled)

此处提供了更多文档:http://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regexoptions(v=VS.90).aspx

答案 2 :(得分:1)

如果您有一组固定的关键字,则可以使用(f)lex,re2cragel

答案 3 :(得分:0)

我建议采取措施:

1)使用string.Split进行令牌并与您拥有的键词典进行匹配

2)使用ReadToken()方法自己为读取器实现tokenizer,它将字符添加到缓冲区,直到找到(Split可能正在执行此操作)拆分字符并将其作为标记输出。然后你检查你的字典。

答案 4 :(得分:0)

也许它有点过于强大,但你一定要看看ANTLR