google搜索拼写纠正
拼写纠正
一直以来用google reader订阅了大量的东西,加星了很多,但有些没怎么认真看过,这几天翻了翻以前的加星,发现一篇讲拼写纠正的文章讲的非常犀利,就像google里那样能够快速准确的纠正拼写。而且作者用python写的代码,只用了21行就完成了。
http://norvig.com/spell-correct.html 原文章在这里
具体的东西可以去看英文原文,这里简单描述下犀利的思想。
我们纠正单词的目的就是希望这样一个条件概率达到最大值P(我们猜测用户想输的单词|用户数的单词),于是我们有
P(我们猜测用户想输的单词|用户数的单词)=P(我们猜测用户想输的单词∩用户数的单词)/P(用户数的单词)
由贝叶斯公式变形可得=P(用户数的单词|我们猜测用户想输的单词)*P(我们猜测用户想输的单词)/P(用户数的单词)
注意到P(用户数的单词)是一定的(因为用户已经输入了嘛)
最后=P(用户数的单词|我们猜测用户想输的单词)*P(我们猜测用户想输的单词)
为什么要这样变化呢,注意到原问题的概率我们很难入手,而转变问题后,问题变得容易处理。
P(我们猜测用户想输的单词)就可以认为是字典里单词出现的频率,而P(用户数的单词|我们猜测用户想输的单词)这一项我们认为对于和原单词的编辑距离(通过增删改或者改变相邻字母的顺序的最少步骤把一个单词变为另一个叫编辑距离)越小的概率越大,为了简化问题作者只考虑了编辑距离是1和2的,因为这已经覆盖了绝大部分的错误。
最后做了个主观臆断,就是说如果用户输的是正确的单词就认为用户没有出错,如果可以经过编辑距离1的变化成正确单词,那么从中找一个能够变成的,正确的,在字典里出现频率最高的单词,如果找不到距离为1的,再找距离为2的,再找不到就认为用户输入了正确单词(比如可能是专有名词或人名等而在字典里找不到)。
就这样通过简短的代码,利用了贝叶斯定理神奇的解决了这个问题。
然后学习了别人的写法自己写了个php版本的,网址是http://spell.isnowfy.com/
-
<?php
-
class Corrector{
-
private static $NWORDS;
-
static function words($text){
-
$matches = preg_match_all("/[a-z]+/", strtolower($text), $output);
-
return $output[0];
-
}
-
static function train($text){
-
foreach($text as $word)
-
@$model[$word] += 1;
-
return $model;
-
}
-
static function read(){
-
if(!file_exists('serialized_dictionary.txt')){
-
$NWORDS = train(words(file_get_contents("big.txt")));
-
$fp = fopen("serialized_dictionary.txt", "w+");
-
fwrite($fp, serialize($NWORDS));
-
fclose($fp);
-
}else
-
$NWORDS = unserialize(file_get_contents("serialized_dictionary.txt"));
-
return $NWORDS;
-
}
-
static function edits1($word){
-
$alphabet = 'abcdefghijklmnopqrstuvwxyz';
-
$alphabet = str_split($alphabet);
-
$n = strlen($word);
-
$edits = array();
-
for($i = 0;$i < $n;$i++){
-
$edits[] = substr($word, 0, $i) . substr($word, $i + 1); //delete
-
if($i < $n-1)
-
$edits[] = substr($word, 0, $i) . $word[$i + 1] . $word[$i] . substr($word, $i + 2); //transposes
-
foreach($alphabet as $c){
-
$edits[] = substr($word, 0, $i) . $c . substr($word, $i + 1); //replaces
-
$edits[] = substr($word, 0, $i) . $c . substr($word, $i); //insert
-
}
-
}
-
foreach($alphabet as $c)
-
$edits[] = substr($word, 0, $n) . $c; //insert n+1
-
return $edits;
-
}
-
static function known($words){
-
$known = array();
-
foreach($words as $w)
-
if(array_key_exists($w, self :: $NWORDS))
-
$known[] = $w;
-
return $known;
-
}
-
static function known_edits2($word){
-
$known = array();
-
foreach(self :: edits1($word) as $e1)
-
foreach(self :: edits1($e1) as $e2)
-
if(array_key_exists($e2, self :: $NWORDS))
-
$known[] = $e2;
-
return $known;
-
}
-
static function getmax($words){
-
$max = 0;
-
$ret = "";
-
foreach($words as $w){
-
if(($temp = self :: $NWORDS[$w]) > $max){
-
$max = $temp;
-
$ret = $w;
-
}
-
}
-
return $ret;
-
}
-
static function correct($word){
-
if(empty(self :: $NWORDS))
-
self :: $NWORDS = self :: read();
-
$word = strtolower(trim($word));
-
if(empty($word))
-
return;
-
if(self :: known(array($word)))
-
return $word;
-
elseif(($temp = self :: known(self :: edits1($word))))
-
return self :: getmax($temp);
-
elseif(($temp = self :: known_edits2($word)))
-
return self :: getmax($temp);
-
else
-
return $word;
-
}
-
}
-
?>