Navigace

Hlavnφ menu

 

Vyhledßvßnφ v textu pomocφ regulßrnφch v²raz∙

ObΦas jsme postaveni p°ed ·kol vyhledat v urΦitΘm textu konkrΘtnφ data urΦitΘho typu. M∙₧e se jednat nap°φklad o vyhledßnφ (respektive vypsßnφ) vÜech odkaz∙ Φi obrßzk∙ obsa₧en²ch ve zdrojovΘm k≤du webovΘ strßnky nebo t°eba vyhledßnφ vÜech e-mail∙ v XHTML k≤du Φi tisφckrßt p°eposlanΘm e-mailu.

Prßv∞ takovΘ ·koly bude °eÜit naÜe PHP t°φda cReex (regular expressions extractor). A co ₧e to p°esn∞ bude d∞lat? Konstruktor t°φdy zφskß (vyextrahuje) z textu (nap°φklad z textu e-mailu) po₧adovanΘ ·daje (nap°φklad e-mailovΘ adresy) a ulo₧φ je do pole. S tφmto polem pak pracujφ dalÜφ metody zajiÜ¥ujφcφ:

  • p°evod vÜech nalezen²ch ·daj∙ na malß pφsmena - eLower()
  • odstran∞nφ duplicitnφch ·daj∙ z pole - eUnique()
  • t°φd∞nφ pole s nalezen²mi ·daji (podle libovolnΘ t°φdφcφ funkce) - eSort(string t°φdφcφ_funkce)
  • tisk (zobrazenφ) nalezen²ch ·daj∙ jako seznam s u₧ivatelsky definovan²m odd∞lovaΦem - ePrint(string odd∞lovaΦ)

Konstruktor t°φdy mß dva argumenty - nßzev prom∞nnΘ obsahujφcφ text, v n∞m₧ se mß vyhledßvat a regulßrnφ v²raz, kter² postihuje libovoln² konkrΘtnφ hledan² ·daj (tedy nap°φklad URL Φi e-mailovou adresu). V²stupem pak bude pole obsahujφcφ vÜechny ·daje (data) obsa₧enΘ v textu a odpovφdajφcφ regulßrnφmu v²razu.

class cReex
{
var $RE; //regulßrnφ v²raz slou₧φcφ k vyhledßvßnφ, resp. parsovßnφ textu
var $Text; //prohledßvan² (vstupnφ) text
var $arFound; //pole obsahujφcφ nalezenΘ ·daje (data)

function cReex($InpText, $RegExp)
{
    ...
}

...jednotlivΘ metody
};

St∞₧ejnφ prßci (tedy extrakci ·daj∙ z textu) provede rovnou konstruktor p°i vytvo°enφ objektu. Tato Φßst si ale zaslou₧φ podrobn∞jÜφ popis. V zßjmu srozumitelnosti i pro mΘn∞ zkuÜenΘho programßtora si dovolφm krßtk² exkurz do pou₧φvßnφ funkce eregi.

Funkce eregi() (co₧ je case insensitive verze funkce ereg()) slou₧φ ke zjiÜt∞nφ, zda zadan² text odpovφdß zadanΘmu regulßrnφmu v²razu, ale navφc umφ "rozsekat" (rozparsovat) zadan² text podle regulßrnφho v²razu, pokud takov² regulßrnφ v²raz obsahuje "uzßvorkovanΘ" subv²razy.

Jak °φkß PHP manußl, funkce eregi(string pattern, string string [, array regs]) mß tedy dva povinnΘ parametry (pattern - regulßrnφ v²raz, string - text, kter² mß regulßrnφmu v²razu odpovφdat) a jeden nepovinn². Nepovinn² parametr regs oznaΦuje prom∞nnou (pole) do nφ₧ majφ b²t ulo₧eny Φßsti textu (string) odpovφdajφcφ jednotliv²m Φßstem (subv²raz∙m) regulßrnφho v²razu (pattern).

Nap°φklad $pattern="^(.{5})(.*)$", $string je text, v n∞m₧ budeme vyhledßvat, p°iΦem₧ zavolßme funkci eregi($pattern, $string, $regs). Pokud $string odpovφdß regulßrnφmu v²razu $pattern (v naÜem p°φpad∞ libovoln² °et∞zec o minimßlnφ dΘlce p∞ti znak∙) funkce vrßtφ TRUE a do pole $regs budou ulo₧eny Φßsti textu $string odpovφdajφcφ "uzßvorkovan²m" subv²raz∙m, p°iΦem₧ text odpovφdajφcφ prvnφmu subv²razu bude v $regs[1] a text odpovφdajφcφ druhΘmu subv²razu v $regs[2]. Text odpovφdajφcφ celΘmu regulßrnφmu v²razu je v₧dy ulo₧en v $regs[0].

Po exkurzi do pou₧φvßnφ funkce eregi() (resp ereg()) se m∙₧eme vrßtit zp∞t k naÜemu problΘmu. Pokud byste vÜak m∞li zßjem o hlubÜφ proniknutφ do pou₧φvßnφ funkce eregi() (resp ereg()) s regulßrnφmi v²razy obsahujφcφmi subv²razy, doporuΦuji vßm Φlßnek Regulßrnφ v²razy v praxi - subv²razy.

Obecn∞ pou₧itelnΘ °eÜenφ budeme pro nßzornost demonstrovat na vyhledßvßnφ e-mailov²ch adres v libovolnΘm textu. Podφvejme se nejd°φve na k≤d konstruktoru:

function cReex($InpText, $RegExp)
{
    $this->RE="(".$RegExp.")(.*)$";
    $this->Text=$InpText;
    $this->arFound=array();
    
    while(eregi($this->RE,$this->Text,$regs))
    {
        array_push($this->arFound,$regs[1]);
        $this->Text=$regs[2];
    };
}

V prom∞nnΘ $InpText je ulo₧en text, v n∞m₧ se vyhledßvß, $RegExp obsahuje regulßrnφ v²raz pro e-mail ([a-zA-Z0-9._-]+@[a-zA-Z0-9.-]{2,}\.[a-zA-Z]{2,4}). Prom∞nnß $this->RE je potom slo₧ena z regulßrnφho v²razu pro e-mail a regulßrnφho v²razu (.*) pro libovoln² text libovolnΘ (i nulovΘ) dΘlky. Pokud se v $InpText nachßzφ alespo≥ jeden e-mail, bude $this->Text odpovφdat regulßrnφmu v²razu $this->RE a navφc bude samotnß e-mailovß adresa odpovφdat prvnφ uzßvorkovanΘ Φßsti (subv²razu) regulßrnφho v²razu a Φßst (zbytek) textu za nalezen²m e-mailem p°ipadne na druhou uzßvorkovanou Φßst. V prom∞nnΘ $regs[1] tak bude prßv∞ nalezen² e-mail a v $regs[2] veÜker² text nßsledujφcφ za tφmto e-mailem.

Nynφ se m∙₧eme podφvat na cyklus, kter² postupn∞ najde a ulo₧φ vÜechny e-maily nalezenΘ ve vstupnφm textu. Cyklus pob∞₧φ, dokud text, v n∞m₧ se mß e-mail hledat, odpovφdß regulßrnφmu v²razu $text->RE, tedy dokud (neprohledan²) text obsahuje alespo≥ jeden e-mail. V ka₧dΘm pr∙chodu cyklem se:

  • nalezen² e-mail (kter² bude v₧dy v $regs[1]) ulo₧φ do pole $this->arFound
  • text, v n∞m₧ se mß v dalÜφm pr∙chodu vyhledßvat, zkrßtφ o prßv∞ nalezen² e-mail, respektive nov²m $this->Text textem se stane Φßst textu za nalezen²m e-mailem, kterß je k dispozici v $regs[2]

St∞₧ejnφ Φßst mßme za sebou, m∙₧eme se tedy podφvat na metody, kterΘ prßci s nalezen²mi ·daji usnadnφ.

U metody eLower() nenφ snad komentß° ani t°eba. Pomocφ foreach a funkce strtolower() se provede p°evod na malß pφsmena u vÜech prvk∙ pole $this->arFound.

function eLower()
{
    foreach($this->arFound as $key=>$value)
    {
        $this->arFound[$key]=strtolower($this->arFound[$key]);
    }
}

Metoda eUnique() je snad jeÜt∞ prostÜφ. Pou₧itß funkce PHP array_unique() z pole odstranφ duplicitnφ hodnoty. KonkrΘtn∞ v p°φpad∞ e-mail∙ je vhodnΘ nejd°φve volat metodu eLower() a a₧ potΘ eUnique(), proto₧e array_unique() je case sensitive a tak pova₧uje e-maily "honza@inmail.cz" a "Honza@inmail.cz" za dva rozdφlnΘ.

function eUnique()
{
    $this->arFound=array_unique($this->arFound);
}

Metoda eSort() t°φdφ vyhledanΘ ·daje (v naÜem p°φpad∞ e-maily) s pou₧itφm zadanΘ t°φdφcφ funkce. Nßzev t°φdφcφ funkce je jedin²m (nepovinn²m) parametrem tΘto metody. Pokud nebude parametr zadßn nebo bude zadßn nßzev neexistujφcφ funkce, bude t°φd∞no implicitn∞ pomocφ funkce sort(). Pokud budete chtφt t°φdit pomocφ jinΘ t°φdφcφ funkce, nap°φklad t°φdit sestupn∞ pomocφ funkce rsort(), staΦφ zavolat $this->eSort("rsort").

function eSort($sort_function="sort")
{
    if (!function_exists($sort_function)) $sort_function="sort";
    $sort_function($this->arFound); 
}

Metoda ePrint() by snad takΘ ani komentß° nevy₧adovala. Jednß se de facto jen o pou₧itφ funkce implode(string odd∞lovaΦ, array pole), kterß spojuje prvky pole do °et∞zce pomocφ odd∞lovaΦe. Metoda ePrint() mß jedin² (nepovinn²) parametr, a to prßv∞ odd∞lovaΦ jednotliv²ch nalezen²ch ·daj∙ (v naÜem p°φpad∞ e-mail∙).

function ePrint($delim="\n")
{
    echo implode($delim,$this->arFound);
}

Tuto t°φdu si pak m∙₧eme ulo₧it t°eba do souboru cReex.php a includovat ji v₧dy, kdy₧ budeme pot°ebovat jejφ slu₧by. Minimalistickß ukßzka pou₧itφ by pak mohla mφt tento k≤d:

include("cReex.php");
$RegExp="[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]{2,}\.[a-zA-Z]{2,4}";
$InpText="nesmysly honza@inmail.cz taky to nenφ e-mail";

$seznam=new cReex($InpText, $RegExp);
$seznam->eLower();
$seznam->eUnique();
$seznam->eSort("natsort");
$seznam->ePrint(", ");

Rozhodn∞ netvrdφm, ₧e by nebylo jeÜt∞ co p°idat. Jednß se o ukßzku °eÜenφ, kterou si ka₧d² m∙₧e dotvo°it tak, aby vyhovovala jeho specifick²m po₧adavk∙m . Pro ·plnost jeÜt∞ doplnφm, ₧e:

  • popsanΘ °eÜenφ je jednφm z n∞kolika mo₧n²ch (alternativou je nap°φklad pou₧itφ PCRE funkce preg_match_all() namφsto postupnΘho zφskßvßnφ e-mail∙ pomocφ funkce eregi() ve while cyklu)
  • v ukßzce uveden² regulßrnφ v²raz popisujφcφ e-mailovou adresu nenφ zcela dokonal² (preciznφ °eÜenφ by toti₧ vy₧adovalo docela obsßhlΘ vysv∞tlenφ, co₧ nenφ p°edm∞tem tohoto Φlßnku)

Kompletnφ zdrojov² k≤d t°φdy je vßm k dispozici v ZIP archivu. Co se s touto t°φdou a trochou snahy dß dokßzat, m∙₧ete vid∞t na p°φkladu aplikace Email Extractor.

Pecka, Miroslav (7. 12. 2004)

Regulßrnφ v²razy v PHP podle POSIX

Regulßrnφ v²razy jsou tφm nejmocn∞jÜφm nßstrojem pro prßci s textem, znaky, °et∞zci. I s elementßrnφ znalostφ jejich princip∙ se vßm otev°e ÜirokΘ pole nov²ch mo₧nostφ a budete schopni °eÜit ·lohy jin²mi mechanismy ne°eÜitelnΘ. Tato sΘrie Φlßnk∙ ji₧ byla uzav°ena, aΦkoli dalÜφ pokraΦovßnφ nelze vylouΦit.