前几天在微博上看到了谷歌某位写的一篇博客,如何写一个小巧的单词拼写检查器:http://norvig.com/spell-correct.html
由于英语水平的限制,以及不了解python,所以这边文章不敢保证和原文的思想完全一致。
我对原文的一些细节的地方,做了细微的修改(尽量不影响效果)。最大的一处修改为编辑距离,原文计算了编辑距离为2的所有单词,而这儿我只计算了距离为1的单词。(可以对我的代码稍作修改从而达到距离为2的单词:递归调用Enum函数)
不扯了,上干货---
用户输入一个单词w,返回一个正确的单词c(有可能为w),使得这种c(输入w的情况下)尽可能合理。
原理主要是贝叶斯概率公式,可以参见原文,这儿直接给出算法。
1.如果用户输入的w存在我们的语料库中,即可认为w是一个正确的单词(语料库的限制,不100%正确),故直接返回w;
2.如果w不存在语料库中,对w作距离为1的编辑,该编辑过程如下:
---删除。 每次删除w中的一个字符,于是我们得到若干个单词. 如abc, 我们可以得到bc,ac,ab三个新的单词,他们与原单词距离为1
---交换。依次交换每相邻的两个字符,如abc,我们可以得到bac acb。
---增加。每次增加一个新的字符(从a到z)如abc,我们可以得到多个单词,不一一列举:aabc,babc,cabc......aabc,abbc.......
---修改。对每个原单词的字符,用abc去替代原字符。 如abc, 我们可以得到,不一一列举:bbc,cbc,zbc......abd,abk,abz....
3.通过步骤2,我们得到若干个编辑距离为1的单词,对这些单词,统计在语料库中出现的次数,哪个单词出现次数最多,则返回该单词给用户。
注,原文统计了距离为2的单词,可以在上面第二部后得出的单词,递归调用Enum函数(需做小修改),从而得到距离为2的单词。
完整工程文件:http://download.csdn.net/detail/owen_kop/5272516
(工程文件有一行代码有问题,请用下面的代码直接覆盖)
可以在vs2010下直接编译运行,包含语料库(model.txt)
截图
源码:
#include "stdafx.h"
typedef struct node
{
string correctWord;
int count;
}correction;
void TrainModel();
void Enum(string input);
void Judge(string s);
correction c;
map dic;
int _tmain(int argc, _TCHAR* argv[])
{
cout<<"wanna quit,click x\n";
cout<<"training model, it may take one or two minutes\n";
TrainModel();
string input;
while(true)
{
cout<<"input:";
c.count=-1;
cin>>input;
if(dic.count(input)>0)
cout<<"correct!"<>s)
{
string temp(s);
if(dic.count(temp)==0)
{
dic[temp]=1;
}
else
{
int count=dic.at(temp);
dic[temp]=(count+1);
}
}
}
void Enum(string input)
{
char set[27]="abcdefghijklmnopqrstuvwxyz";
int length=input.length();
// delete
for(int i=0;ic.count)
{
c.count=number;
c.correctWord=s;
}
}