RU
   

Определение языка и кодировки. Компонент для CakePHP

rss
Материал скопирован.., источник ниже..

Для моего текущего проекта необходимо определять на каком языке пользователь вводит информацию. Причём это не сложный выбор между PHP и Perl, а, например, между английским и испанским. Сначала я хотел составить список самых распространённых слов в популярных языках - предлоги, частые глаголы и т.д. Почти сразу я понял, что точность будет небольшая, а работы - очень много, даже, если её буду делать не я :).
Поэтому пришлось думать дальше. Мне больше всего понравился способ, в котором учитывается частотность букв, двух-, трёх- и четырёхбуквенных сочетаний.

Сначала система обучается - ей скармливается много текста и указывается, какой это язык. Она разбирает их на части и запоминает наиболее часто встречаемые как эталонные для этого языка.

Потом берётся текст с неизвестным языком и определяются наиболее часто встречаемые части в нём. Эти части сравниваются с эталонными и на основе этого определяется вероятность каждого из языков.

Я взял за основу код с http://boxoffice.ch/pseudo/ng.php, удалил лишнее, немного оптимизировал алгоритм и сделал код красивый и подходящий для CakePHP.

Определим язык для текста
<?php
$language 
$this->LangDetect->detect('Учи олбанский и убей сибя ап стену.');
?>


Не каждый человек сможет понять, что это за язык :). А компонент понял - russian-utf8.
Кстати, сразу видно бонус - определяется кодировка. Для русского поддерживаются ISO, KOI8-R, UTF-8, Windows-1251.

Если надо определить несколько наиболее вероятных языков, то надо указать второй параметр true.
<?php
$language 
$this->LangDetect->detect('Учи олбанский и убей сибя ап стену.'true);
?>


Это выдаст:
<?php
Array 

    [
russian-utf8] => 30366 
    
[bulgarian-utf8] => 31619 
    
[ukrainian-utf8] => 33273 
    
[serbian_cyrillic-utf8] => 33878 
    
[belarusian-utf8] => 35596 
...
?>


Чем меньше значение, тем более вероятно, что это тот язык.

Полный список поддерживаемых языков (можно получить с помощью $this->LangDetect->listLanguages()):
afrikaans, albanian, alemannic, amharic-utf8, arabic-iso8859_6, arabic-utf8, arabic-windows1256, armenian, armenian-utf8, basque, belarusian-utf8, belarusian-windows1251, bosnian, breton, bulgarian-iso8859_5, bulgarian-utf8, catalan, chinese-big5, chinese-gb2312, chinese-utf8, croatian-ascii, czech-iso8859_2, czech-utf8, danish, dutch, english, esperanto, estonian, finnish, french, frisian, georgian, georgian-utf8, german, greek-iso8859_7, greek-utf8, hawaian, hebrew-iso8859_8, hebrew-utf8, hindi, hindi-utf8, hungarian, icelandic, indonesian, irish_gaelic, italian, japanese-euc_jp, japanese-shift_jis, japanese-utf8, korean, korean-utf8, latin, latvian, lithuanian, malay, manx, marathi, marathi-utf8, middlefrisian, mingo_iroquois, nepali, nepali-utf8, norwegian, persian, persian_farsi-utf8, persian_farsi-windows1256, polish-iso8859_2, polish-utf8, portuguese_brazil, portuguese_europe, quechua, romanian, rumantsch, russian-iso8859_5, russian-koi8_r, russian-utf8, russian-windows1251, sanskrit, scots, scots_gaelic, serbian-ascii, serbian_cyrillic-utf8, slovak-ascii, slovak-utf8, slovak-windows1250, slovenian-ascii, slovenian-iso8859_2, spanish, swahili, swedish, tagalog, tamil, tamil-utf8, thai, thai-utf8, turkish, turkish-utf8, ukrainian-koi8_u, ukrainian-utf8, vietnamese, welsh, yiddish-utf8

Чтобы компонент заработал, нужно скачать скомпилированную информацию о языках и положить этот fingerprint.dat в app/vendors.

А вот и сам компонент:

<?php
/** 
* Language detection component 

* Most of code was copied from http://boxoffice.ch/pseudo/code_expl/code_class.php 
* but a lot of things were simplified and beautified 

* @link http://php.southpark.com.ua 
* @author Vladimir Luchaninov 
* @version 1.0 (3 Dec 2007) 

*/ 
class LangDetectComponent 
    protected 
$fingerprint null
    protected 
$ngrams = array(); 
  
    
//reasonable defaults 
    
public $ngramCount 350;     //default nb of ngrams created from analyzed text 
    
public $maxDelta 140000;    //stop evaluation deviate strongly 
  
    
function startup(&$controller) { 
        
$this->fingerprint unserialize(file_get_contents(APP 'vendors' DS 'fingerprint.dat')); 
    } 
  
    
/** 
     * Main function 
     * 
     * @param string $text Text with unknown language 
     * @param bool $onlyBest 
     *   true - detect the best language 
     *   false - detect all languages with possibilities 
     * @return LangDetect 
     */ 
    
function detect($text$onlyBest true) { 
        if (empty(
$text)) { 
            
trigger_error('Text should not be empty'); 
            return 
false
        } 
  
        
$this->createNGrams($text); 
  
        if (
$onlyBest){ 
            return 
$this->compareNGramsOne(); 
        } else { 
            return 
$this->compareNGrams(); 
        } 
    } 
  
    
/** 
     * Get list of the available languages 
     * 
     * @return array List of languages 
     */ 
    
function listLanguages() { 
        
$languages array_keys($this->fingerprint); 
        
sort($languages); 
        return 
$languages
    } 
  
    
/** 
     * Create ngram-array of given string 
     * 
     * @param string $text 
     * 
     */ 
    
protected function createNGrams($text) { 
        
$array_words explode(" "$text); 
        
$ngrams = array(); 
        foreach(
$array_words as $word) { 
            
$word "_"$word "_"
            
$wordLength strlen($word); 
            for (
$i=0$i <$wordLength$i++) { //start position within word 
                
for ($s=1$s <4+1$s++) {  //length of ngram 
                    
if (($i $s) <$wordLength 1) { //length depends on postion 
                        
$ngrams[] = substr($word$i$s); 
                    } 
                } 
            } 
        } 
  
        
//count-> value(frequency, int)... key(ngram, string) 
        
$blub array_count_values($ngrams); 
  
        
//sort array by value(frequency) desc 
        
arsort($blub); 
  
        
//use only top frequent ngrams (def by $ng_number) 
        
$top array_slice($blub0$this->ngramCount); 
  
        
$this->ngrams = array(); 
        foreach (
$top as $keyvar => $valvar){ 
            
$this->ngrams[] = $keyvar
        } 
    } 
  
    
/** 
     * Compare ngrams: Textinput vs lm-files. 
     * 
     * @return array of languages with lowest deviation 
     */ 
    
protected function compareNGrams() { 
        
$limit $this->maxDelta
        foreach (
$this->fingerprint as $basename => $language) { 
            
$delta 0
            
//compare each ngram of input text to current lm-array 
            
foreach ($this->ngrams as $key => $ngram){ 
                
//match 
                
if(in_array($ngram$language)) { 
                    
$delta += abs($key array_search($ngram$language)); 
                    
//no match 
                
} else { 
                    
$delta += 400
                } 
                
//abort: this language already differs too much 
                
if ($delta$this->maxDelta) { 
                    break; 
                } 
            } 
// End comparison with current language 
  
            //include only non-aborted languages in result array 
            
if ($delta <($this->maxDelta)-400) { 
                
$result[$basename] = $delta
            } 
        } 
//End comparison all languages 
  
        
if(!isset($result)) { 
            
$result = array('unknown'=>0); 
        } else { 
            
asort($result); 
        } 
  
        return 
$result
    } 
  
    
/** 
     * Variation - COMPARE ng's - Return 1 LANGUAGE only 
     * 
     * @return string Most probable language 
     */ 
    
protected function compareNGramsOne() { 
        
$limit 160000
        foreach (
$this->fingerprint as $basename => $language) { 
            
$delta 0
            foreach (
$this->ngrams as $key => $ngram){ 
                if (
in_array($ngram$language)) { 
                    
$delta += abs($key array_search($ngram$language)); 
                } else { 
                    
$delta += 400
                } 
                if (
$delta$limit) { 
                    break; 
                } 
            } 
  
            if (
$delta <$limit) { 
                
$result[$basename] = $delta
                
$limit $delta//lower limit 
            

        } 
  
        if (!isset(
$result)) { 
            return 
'unknown'
        } else { 
            
asort($result); 
            
//basename of best matching lm file 
            
list($result_first$ignore) = each($result); 
        } 
  
        return 
$result_first
    } 
  
}
?>



Источник : http://php.southpark.com.ua/2007/language-detection/
 
Дата добавления: 2009-11-24 11:16:59, просмотров: 7407
Комментарии: 0
Пожалуйста, авторизируйтесь, для возможности добавить комментарий..
Copyright © 2011 - 2024 forwebm.net
 
Яндекс цитирования
Поддержка
E-mail: Задать вопрос ,

Рейтинг@Mail.ru

Создание сайта: forwebm.net