单词纠错算法成功应用于澳典网在线英汉词典,但尚可改进
当用户输入一个单词的时候,我们首先要判断这个单词正确与否,判断的依据就是看看它是否存在于我们既有的词典中。(根据后台数据显示,目前澳典在线英汉词典收词量达135,277条,包括缩写词、单词原型,不包括词组。据了解,《牛津现代英汉双解词典》收词量也是在13万这样一个数量级,《牛津高阶英汉双解词典》收词量在8万左右。)如果单词不存在,则表明这个单词可能输入错误,我们需要给出一些和这个输错的单词“相似”的正确单词。这个找寻“相似”的正确单词的过程就要用到我们的单词纠错算法。
用户输入错误是有一些特点的,例如多一两个字母或者少一量个字母,还有可能是记错了或者打字太快输错了几个字母,最后是用户输入的是单词的变形形式(如第三人称单数、复数形式、现在分词、过去分词、一般过去时、比较级、最高级等等)不在我们的字典库中。所以首先我们使用了一个“二次相似匹配”的算法,以用户输入的“单词”(一个字符串)为基准,从词典中取出一部分“比较”相似的单词,我们要确保用户真正想要的单词就在其中。这一步得到的单词数量在一到数千的的样子,由于使用了索引,执行时间为毫秒级。注意我们使用的“二次相似匹配”和网上介绍的“骨架键”是完全不同的。
现在我们取回这样一大堆“相似”的单词,下面就要对这一大堆单词进行比对,看看他们和用户输错的单词有多像,并进行排序,然后取出前10个或者前n个呈现给用户(我们实际操作中是取前15个)。我们在单词比较中有如下的考虑:
1、两个单词具有连续相同字母越多越相似(最大公共子串的概念);
2、在最大公共子串的前提下,两个单词具有相同的字母越多越相似;
3、两个单词长度越接近越相似(对一个10字母的错词来说,显然9个字母的单词要比6个字母的单词更“像”一些;
4、我们将字符的ascii码之和为单词定义权重(weight),权重越接近,单词越相似(也可以用字母顺序a-1,b-2,……,z-26来定义权重);
以上3、4两点实现起来很简单,1、2两点之要做一个矩阵(二维数组),对于对角线上的空格,字母不同处置0,字母相同处+1,看下面的图例:
| f | o | r | e | v | e | r | |
| r | 0 | 0 | 1 | 0 | 0 | 0 | 1 |
| i | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| v | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
| e | 0 | 0 | 0 | 1 | 0 | 2 | 0 |
| r | 0 | 0 | 1 | 0 | 0 | 0 | 3 |
用一个二重循环轻松搞定。至此可得到两个单词的大公共子串表,同时也标注出了其“相似”的权重,显然1越多越好,数值越大越好,因为数值越大意味这公共字串越长。计算这张表上所有数字的平方和,得到数值A,A越大,两个单词越相似;计算两个单词的长度差D,D越小,两个单词越相似;计算量个单词的权重差W,W越小,两个单词越相似。通过A、W、D三者之间的一个算法关系,我们可以比较准确地计算出单词的相似度,以此排序,就能得到我们要的结果了。
看一下我们的成果,貌似还不错:
http://odict.net/pistachou/ -> pistachio(开心果)
http://odict.net/apointment/ -> appointment(约会)
http://odict.net/commision/ -> commission(佣金)
在实际应用中,我们还加上了部分常见后缀判断,例如:http://odict.net/fastest/ -> fast
以上分析算是比较机械式的了,事实上很大一部分输入错误,是由于键盘键位导致(如把w错输成e,把o错输成p),还有一些是相同发音导致(如ss打成s,ear打成eer等)。因此如果能够将键盘工程学和发音学的判定加入上述算法,则结果将更为准确。