<?php /** 事件a:输入正确单词 事件b:输入错误单词 p(a|b):已经输入了错误的单词b,但是想输入的是正确单词a的概率。可以看出在输入一个错误单词b时,就是找到一个p(a|b)概率最大的a,单词a就是所求。 p(b|a):已经输入了正确的单词a,但是可能输入成错误单词b的概率。一般约难拼写的就越高。 p(a):输入正确单词的概率,也就是频率。 p(a|b)=p(b|a)*p(a)/p(b); 答案就是找到一个最大的p(a|b),p(a|b)根据公式,又只和p(b|a)和p(a)有关。 所以,问题的答案就应该是 首先这个词a被写成词b的概率很大,对应p(b|a)很大。一般越是相近的词越有可能被拼错。 其次这个词a的词频很高,对应p(a)很大。 **/ function init($file){ $fp= fopen("http://norvig.com/big.txt","r"); $a = array(); while(!feof($fp)){ $line = fread($fp,1024); $words = preg_split('/ /',$line); foreach($words as $w){ preg_match('/[a-zA-Z]*/',$w,$matches); if(!array_key_exists(strtolower($matches[0]),$a)){ $a[strtolower($matches[0])] = 1; }else{ $a[strtolower($matches[0])] += 1; } } if(count($a)>10000){ break; } } fclose($fp); file_put_contents($file,json_encode($a)); } function load_words($file='word'){ if(!is_file($file)){ init($file); } $data = file_get_contents("word","r"); return json_decode($data,true); } function load_wrong($file='wrong'){ if(!is_file($file)){ $fp = fopen($file,'a+'); fclose($fp); return array(); } $data = file_get_contents("wrong","r"); return json_decode($data,true); } function log_wrong($fix,$w,$file='wrong'){ $data = json_decode(file_get_contents($file),true); if(!isset($data[$fix])){ $data[$fix] = array(); $data[$fix][$w] = 1; }else{ array_key_exists($w,$data[$fix])?$data[$fix][$w]++:$data[$fix][$w]=1; } file_put_contents($file,json_encode($data)); } function distance($str1,$s1,$str2,$s2,$diff=0){ if($diff>=4){ return 99; } if($s1>=strlen($str1)||$s2>=strlen($str2)){ return max(strlen($str2)-$s2,strlen($str1)-$s1); } if($str1[$s1]==$str2[$s2]){ return distance($str1,$s1+1,$str2,$s2+1,$diff); }else{ return min(min(distance($str1,$s1,$str2,$s2+1,++$diff),distance($str1,$s1+1,$str2,$s2,++$diff)),distance($str1,$s1+1,$str2,$s2+1,++$diff))+1; } } function arr_sum($arr){ $sum = 0; foreach($arr as $a){ foreach($a as $sub_a){ $sum += $sub_a; } } return $sum; } function auto_complete($w){ $words = load_words(); $wrong = load_wrong(); $count=0; if(array_key_exists($w,$words)){ return $w; }else{ $fixs = array(); $words_sum = array_sum($words); $wrong_sum = arr_sum($wrong); foreach($words as $word=>$feq){ if(abs(strlen($word)-strlen($w))<3){ $dist = distance($word,0,$w,0); if($dist <= 2){ $fixs[$word] = sqrt($feq/$words_sum); //防止高词频的单词经常被匹配,比如arry会匹配到are而不是array,所以弱化了词频的影响,用sqrt越是高词频被弱化的越明显。 if($wrong[$word][$w]/$wrong_sum!=0){ $fixs[$word] *= $wrong[$word][$w]/$wrong_sum; } $fixs[$word] *= 1/($dist); } } } arsort($fixs); var_dump($fixs); $ret = array_keys($fixs); return $ret[0]; //这里也可也设定一个闸值,大于多少的都返回。 } } $w = "beautifual"; $fix = auto_complete($w); echo '<br>'.$w.'修正结果:'.$fix.'<br>'; /** ***确认单词,假设fix的就是正确的。 **/ if(strcmp($fix,$w)!=0){ log_wrong($fix,$w); } ?>
写着玩而已,里面肯定有很多纰漏,只是写个大概的意思。