实现带有单词建议的拼写检查器时通常使用哪种算法?
起初,我认为检查每个键入的新单词(如果在词典中找不到)相对于其与词典中其他每个单词的Levenshtein距离并返回最佳结果可能是有意义的。但是,这似乎效率很低,必须反复评估整个字典。
通常如何完成?
实现带有单词建议的拼写检查器时通常使用哪种算法?
起初,我认为检查每个键入的新单词(如果在词典中找不到)相对于其与词典中其他每个单词的Levenshtein距离并返回最佳结果可能是有意义的。但是,这似乎效率很低,必须反复评估整个字典。
通常如何完成?
Answers:
彼得·诺维格(Peter Norvig)有一篇很好的文章,介绍如何实现拼写校正器。从根本上讲,这是一种蛮力尝试具有给定编辑距离的候选字符串。(以下是一些技巧,您可以使用布隆过滤器和更快的候选哈希来提高拼写校正器的性能。)
拼写检查器的要求较弱。您只需找出字典中没有单词。您可以使用布隆过滤器来构建拼写检查器,从而减少内存消耗。乔恩·本特利(Jon Bentley)在Programming Pearls中使用64kb作为英语词典来描述一个古老的版本。
Levenshstein距离不是拼写检查器正确的编辑距离。它只知道插入,删除和替换。缺少换位,并为1个字符的换位生成2(即1个删除和1个插入)。Damerau–Levenshtein距离是正确的编辑距离。
生成我已经成功使用过但在任何地方都从未见过的建议的一种方法是使用“不良”哈希函数预先计算建议(在构建字典时)。
这样做的目的是查看人们犯的拼写错误的类型,并设计散列函数,这些散列函数会将错误的拼写分配给与其正确的拼写相同的存储桶。
例如,一个常见的错误是使用错误的元音,例如definate而不是definite。因此,您需要设计一个将所有元音视为相同字母的哈希函数。一种简单的方法是首先对输入的单词进行“规范化”,然后通过常规的哈希函数将规范化的结果放入。在此示例中,归一化功能可能会删除所有元音,因此definite
变为dfnt
。然后用典型的散列函数对“归一化”的单词进行散列。
使用此特殊的哈希函数将所有词典单词插入辅助索引(哈希表)。该表中的存储桶将具有较长的冲突列表,因为哈希函数是“错误的”,但是这些冲突列表本质上是预先计算的建议。
现在,当您找到拼写错误的单词时,您会在辅助索引中查找该拼写错误映射到的存储桶的冲突列表。塔达:您有一个建议清单!您所要做的只是在上面排列单词。
在实践中,您将需要一些带有其他哈希函数的辅助索引来处理其他类型的错误,例如转置字母,单/双字母,甚至是一个简单的类似于Soundex的错误,以捕捉拼写错误。在实践中,我发现简单的发音方式可以走很长一段路,并且实际上已经淘汰了一些旨在查找琐碎错别字的发音。
因此,现在您在每个辅助索引中查找拼写错误,并在排名之前将冲突列表连接起来。
请记住,冲突列表仅包含词典中的单词。使用尝试生成替代拼写的方法(如Peter Norvig文章中所述),您可以获得(成千上万)首先要针对字典进行筛选的数千名候选人。使用预先计算的方法,您可能会获得数百名候选人,而且您知道他们的拼写都正确,因此您可以直接跳到排名。
更新:此后,我发现了一个与此算法类似的算法描述,即FAROO分布式搜索。这仍然是一个编辑距离受限的搜索,但是它非常快,因为预计算步骤的工作原理与我的“错误的哈希函数”想法类似。FAROO仅使用了错误哈希函数的有限概念。
拼写检查器非常容易实现,就像在Unix拼写程序中一样。源代码是公开可用的。可能涉及更正,一种技术是进行编辑,然后再次检查该新词是否在词典中。这样的新编辑可以被分组并显示给用户。
Unix系统使用Mc IllRoy编写的程序。另一种方法是使用Trie,它在文件很大的情况下很有用。
Unix方法由于使用散列散列算法,因此对于大型词典而言,其占用的空间非常少。