拼写纠错

<?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);
}    

?>

写着玩而已,里面肯定有很多纰漏,只是写个大概的意思。

posted @ 2012-10-26 17:58  23lalala  阅读(207)  评论(0编辑  收藏  举报