O regulárních výrazech bylo napsáno velké množství rozsáhlých manuálů. K tomu, abyste se naučili používat regulární výrazy, ale nemusíte pročítat dlouhé odstavce textu, stačí si podrobně projít několik příkladů. Zaměříme se na regulární výrazy používané v PHP podle normy POSIX 1003.2.

Tyto regulární výrazy se v PHP používají ve funkcích ereg(), ereg_replace(),eregi(), eregi_replace(), split() a spliti(). Existují i jiné druhy regulárních výrazů, rozdíl je však minimální a především syntaktický. Regulární výrazy (RV) mají základ v teorii jazyků a jsou také hojně používány např. v systému UNIX.

Regulární výrazy se používají pro určení, zda daný řetězec má určitý formát, resp. patří do nějaké skupiny řetězců. Pak říkáme, že tento řetězec vyhovuje zmíněnému RV. Např. pomocí nich testujeme, zda nějaký řetězec reprezentuje emailovou adresu.

Základní konstrukce

cde vyhovuje každý řetězec osahující slovo cde, tedy např. „abcde“ „cdefg“, „cde“

^ označuje začátek řetězce ^cde   vyhovuje každý řetězec začínající „cde“, např. „cdefg“, „cde“, ale nevyhovuje „abcde“

$ označuje konec řetězce
cde$   vyhovuje každý řetězec končící „cde“ např. „abcde“, „cde“, ale nevyhovuje „cdefg“
^cde$   vyhovuje pouze řetězec „cde“

„.“ zastupuje libovolný znak
^.luh$   vyhovují řetězce „pluh“, „dluh“, nevyhovuje řetězec „dluhy“

„*“ označuje opakování předcházejícího znaku nula- a vícekrát
^ab*$   vyhovují řetězce „a“, ab“, abb“, abbb“, …, řetězec „aabb“ nevyhovuje

„+“ označuje opakování předcházejícího znaku jednou- a vícekrát
^ab+$   vyhovují řetězce ab“, abb“, abbb“, …, řetězec „a“ nevyhovuje

„?“ označuje opakování předcházejícího znaku nula- nebo jedenkrát (nepoviný výskyt)
^ab?$   vyhovují pouze řetězce „a“, ab“

„{2,4}“ označuje opakování předchozího znaku 2 až 4-krát
^ab{2-4}$   vyhovují řetězce „abb“, „abbb“ a „abbbb“
^.{3}$   vyhovují řetězce dlouhé přesně tři znaky (totéž jako ^…$)

{2,} označuje opakování předchozího znaku alespoň 2-krát
* je totéž jako {0,}
+ je totéž jako {1,}
? je totéž jako {0,1}

[] zastupuje jeden znak ze seznamu v závorkách
^a[bcd]$   vyhovují řetězce „ab“, „ac“ a „ad“
^[a-z]*$   vyhovují řetězce složené pouze z malých písmen abecedy
^[a-zA-Z]*$   vyhovují řetězce složené z malých a velkých písmen abecedy
^[a-zA-Z0-9]*$   vyhovují řetězce složené z písmen a číslic
^[1-9]?[0-9]$   vyhovují čísla od 0 do 99

„^“ na začátku seznamu znamená negaci (tedy závorky zastupují jeden znak, který není na seznamu)
^[^0-9]   vyhovují řetězce nezačínající číslicí

Jestliže chcete do seznamu přidat znak „^“, nesmí být na prvním místě. Naopak znak „-“ musí být buď na prvním místě nebo jako pravá mez nějakého intervalu. Znak „]“ musí být také jako první hodnota v seznamu (před ním může předcházet pouze znak negace „^“).

„|“ má význam logického OR
^(b|cd)ef$   vyhovují řetězce „bef“ a „cdef“
^(a|b)*c$   vyhovují řetězce začínající posloupností písmen „a“ a „b“ a končící jedním „c“
(a|b) je totéž, co [ab]
(0|1|2|3|4|5|6|7|8|9) je totéž, co [0-9] a totéž, co [9876540123]

„()“ kulaté závorky slouží k seskupení řetězce. Opakovací značky (*, +, ?) se pak vztahují na celý obsah závorky, ne pouze na jeden znak.
^(abc)*$   vyhovují řetězce „“, „abc“, „abcabc“, abcabcabc“, …

„\.“ označuje znak „.“, „\\“ označuje znak „\“
\.   Vyhovuje libovolný řetězec obsahující alespoň jednu tečku

Chcete-li uvést znaky, které mají speciální význam tj. znaky „^.[$()|*+?{\“, je nutné je zbavit jejich speciálního významu předcházejícím backslash „\“. Výjimkou jsou hranaté závorky, uvnitř nichž znaky ztrácí svůj speciální význam a backslash se nepoužívá.

Kontrola emailové adresy

Ukážeme si, jak by se vytvořil RV pro ověření emailové adresy. V první řadě, jak vypadá emailová adresa? Skládá se ze tří částí – jméno uživatele, zavináč („@“) a jméno serveru. Jméno uživatele může obsahovat malá a velká písmena, číslice, tečky („.“), pomlčku („-„) a podtržítko („_“). Stejné znaky kromě podtržítka může obsahovat i jméno serveru. Jméno uživatele ani jméno serveru navíc nesmí začínat ani končit tečkou a nikde se nesmí vyskytovat dvě tečky za sebou.

Nyní se podívejme, jak by vypadal regulární výraz pro ověření jména.
^[_a-zA-Z0-9-]+$

Tento výraz však zatím nepovoluje tečku. Dále tedy upravujeme:
^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*$

Nyní přidáme zavináč a jméno serveru (kromě podtržítka stejné jako uživatelské jméno):
^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*$

Pokud předpokládáme, že musí mít server alespoň dvě domény (tedy musí obsahovat alespoň jednu tečku), upravíme výraz:
^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)+$

test

Kontrola datumu pro MySQL

MySQL vyžaduje, aby bylo datum zadáno ve formátu rrrr-mm- dd, zadávání dat v jiném formátu by skončilo chybou. MySQL přitom nevyžaduje, aby den dával v kombinaci s měsícem smysl, můžete tedy vkládat i hodnotu 2001-11-31. Rovněž jsou přípustné nulové hodnoty dne a měsíce z důvodu vyjádření neurčitosti. MySQL nevyžaduje u číslovky vodící nulu, můžeme tedy zadávat „2001-09-25“ i „2001-9-25“.

Začneme s konstrukcí RV pro den:
^[0-3]?[0-9]$

tomuto RV však vyhovují i dny jako „36“. Proto rozdělíme výraz na 2 možnosti podle toho, zda je první číslice 3 či nikoli.
^(([0-2]?[0-9])|(3[01]))$

Nyní uděláme podobný výraz pro měsíc …
^((0?[0-9])|(1[012]))$

… přidáme rok a spojíme vše dohromady
^[0-9]{4}-((0?[0-9])|(1[012]))-(([0-2]?[0-9])|(3[01]))$

test

Příklad použití

Tady je příklad, který ukazuje, jak se regulární výrazy v PHP používají v nejjednodušší funkci ereg. Ta zjišťuje, zda řetězec vyhovuje RV.

<?
if (ereg("^[0-9]{4}-((0?[0-9])|(1[012]))-(([0-2]?[0-9])|(3[01]))$", $datum))
   echo „$datum je platné datum pro MySQL.“
   else echo „$datum není platné datum pro MySQL.“
?>

Testování

Na testovací stránce si můžete vyzkoušet své regulární výrazy.

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

2 Příspěvků v diskuzi

Odpovědět