Pspell

Školení, která pořádám

Pspell asi nepatří k nejpoužívanějším rozšířením PHP, já jsem ho ale už dvakrát použil k poměrně zajímavým úkolům. Pspell je rozšíření, které v PHP umožňuje používat kontrolu pravopisu, při instalaci odpovídajícího slovníku i pro češtinu.

Skoro mě až překvapilo, jak jednoduše jde v PHP napsat aplikace pro asistované přidání háčků a čárek do textu bez diakritiky. Pro vytvoření celé aplikace se hodí i dobrá znalost JavaScriptu a pokud možno také statistických metod, z pohledu PHP je ale asi nejzajímavější funkce, která vrátí všechny možné varianty slova bez diakritiky:

<?php
define("ISO_8859_2", "áčďéěíňóřšťúůýžÁČĎÉĚÍŇÓŘŠŤÚŮÝŽ");
define("US_ASCII", "acdeeinorstuuyzACDEEINORSTUUYZ");

/** Vrácení variant slov s diakritikou nalezených ve slovníku
* @param string začešťované slovo obvykle bez diakritiky (stávající diakritika se ponechá)
* @return array správné varianty slova - array("var1", ...)
*/
function zacesti_slovo($slovo) {
    static $pspell;
    if (!isset($pspell)) {
        pspell_config_create("cs");
        $pspell = pspell_new("cs");
    }
    
    static $pismena; // array("a" => "á", "e" => "éě", ...)
    if (!isset($pismena)) {
        for ($i=0; $i < strlen(US_ASCII); $i++) {
            $pismena[substr(US_ASCII, $i, 1)] .= substr(ISO_8859_2, $i, 1);
        }
    }
    
    $moznosti = array("");
    for ($i=0; $i < strlen($slovo); $i++) {
        foreach ($moznosti as $key => $val) {
            $moznosti[$key] .= $slovo[$i];
            for ($j=0; $j < strlen($pismena[$slovo[$i]]); $j++) {
                $moznosti[] = $val . $pismena[$slovo[$i]][$j];
            }
        }
    }
    foreach ($moznosti as $key => $val) {
        if (!pspell_check($pspell, $val)) {
            unset($moznosti[$key]);
        }
    }
    return $moznosti;
}
?>

Elegantní mi přijde obzvláště část, která naplní pole $moznosti všemi možnými variantami slova. Je to sice poměrně hutné čtivo, ale svůj účel splní myslím šikovně. Připomínám, že konstrukce $slovo[$i] se používá pro získání $i-tého znaku řetězce $slovo a odpovídá tedy zápisu substr($slovo, $i, 1).

V druhém případě jsem rozšíření Pspell použil pro kontrolu pravopisu na stránkách, tam ale kromě rozřezání textu na slova a použití správného jazyka v závislosti na hodnotách atributů lang nic až tak zajímavého není.

Jakub Vrána, Seznámení s oblastí, 15.6.2005, diskuse: 7 (nové: 0)

Diskuse

ikona spaze:

Wow, zajimava vec :) Ale chtel bych poprosit o jednu vec. Nemam rad postupy copy/paste, snazim se pouzivanej kod nejdriv pochopit -- a to tvoje husty cteni je opravdu husty, slo by k tomu priste napsat nejakej komentar ve stylu:

<?php
   
// V tomto cyklu vytvarime maly zombiky, zasadime je do pole.
    // V tom poli je pak budeme zalevat, stanou se z nich vetsi zombici,
    // az z nich bude cela armada, ukoncime produkci, jsme tak pripraveni k boji.
    for ($i=0; $i < strlen($slovo); $i++) {
        foreach ($moznosti as $key => $val) {
            $moznosti[$key] .= $slovo{$i};
            for ($j=0; $j < strlen($pismena[$slovo{$i}]); $j++) {
                $moznosti[] = $val . $pismena[$slovo{$i}]{$j};
            }
        }
    }
?>

Rozumim, ze komentar by mohl delsi nez samotnej kod (a ze "A TRUE Klingon warrior does not comment his code!"), ale prece jen by to hodne pomohlo k rychlymu ziskani prehledu o tom, co ten kod vlastne dela. Dik :)

Leo:

A k tomu bych se pridat, komentaru pro nas natvrdlejsi neni nikdy dost, diky predem, Leo

ikona Jakub Vrána OpenID:

Pokusím se, ať to k něčemu je. Ono se PHP dá číst líp než třeba svahilština, ale pro spoustu lidí pořád hůř než čeština :-).

Ten kód postupuje po jednotlivých písmenech proměnné $slovo, ke všem existujícím prvkům v poli $moznosti přidá aktuální písmeno (bez diakritiky) a následně do pole přidá možnosti vzniklé doplněním diakritiky. Takže z řetězce "ale" vznikne postupně:

array("a", "á")
array("al", "ál")
array("ale", "ále", "alé", "alě", "álé", "álě")

ikona spaze:

.. a pokud jsem to pochopoval spravne, tak se potom kazdej ten prvek vzniklyho pole prozene pspell_check()-em, jestli takovy slovo existuje v danym jazyce -- takze treba slova jako "álě" se unset()nou. Hmm, chytry vyuziti spellcheckeru ;)

___
ne, ze by PHP bylo pro me svahilstinou, ale mozna i ty sam za pul roku bys svuj komentar ocenil ;) (bez urazky, samo)

peta:

Souhlasím s tebou, kód příkladu jsem si prošel a postupně jsem si ho přepsal do srozumitelnější podoby. Sice je o nějakých deset řádků delší, možná je i o pár setinek pomalejší, ale alespoň bude dobře čitelný i po delší době...

Orrorin:

až na tu exponenciální složitost dobrý

ikona Jakub Vrána OpenID:

Dobrá poznámka. Složitost je exponenciální vzhledem k délce slova, která je omezená, takže je to i tak schopné provozu. Složitost by se dala významně srazit, pokud bychom měli přímý přístup ke všem slovům s diakritikou. Pokud máme k dispozici pouze funkci pspell_check(), tak to vylepšit podle mě nepůjde.

Vložit komentář

Používejte diakritiku. Vstup se chápe jako čistý text, ale URL budou převedeny na odkazy a PHP kód uzavřený do <?php ?> bude zvýrazněn. Pokud máte dotaz, který nesouvisí s článkem, zkuste raději diskusi o PHP, zde se odpovědi pravděpodobně nedočkáte.

Jméno: URL:

avatar © 2005-2018 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.