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.
{
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:
{
$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.
{
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Θ.
{
$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").
{
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∙).
{
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:
$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φ funkceeregi()
vewhile
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.
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.
- Vyhledßvßnφ v textu pomocφ regulßrnφch v²raz∙ (prßv∞ Φtete)
- Regulßrnφ v²razy v praxi - subv²razy
- Regulßrnφ v²razy v p°φkladech
- Regulßrnφ v²razy v PHP (2.)
- Regulßrnφ v²razy v PHP (1.)