Perl-compatible regulární výrazy v PHP - modifikátory a líné kvantifikátory
V předchozím článku jsme nakousli téma modifikátorů, a protože modifikátory jsou příliš velkým soustem pro jeden článek, budeme v tomto tématu pokračovat a ukážeme si další čtyři modifikátory.
"Single line"
Jak jsem psal již v prvním článku, metaznaku . (tečka) odpovídají všechny znaky kromě \n. Pokud je však použit modifikátor "single line" (který má ovšem v PHP interní označení "PCRE_DOTALL"), metaznak . bude odpovídat i znaku konce řádku \n. Modifikátor "single line" má zkratku "s".
"Extended" aneb komentáře v regulárních výrazech
Pokud použijeme modifikátor "extended" (který má zkratku "x"), způsobí to dvě změny ve vyhodnocování regulárního výrazu:
- Takzvané "bílé znaky" v regulárním výrazu budou ignorovány, s výjimkou bílých znaků zapsaných v rámci skupiny znaků a s výjimkou případu, kdy bílému znaku bude předcházet zpětné lomítko \.
- Část regulárního výrazu vpravo od znaku # až po znak konce řádku \n (včetně) bude ignorována. To umožňuje vkládat ve složitých regulárních výrazech komentáře za znak #.
Použití předvedu opět na ukázce:
$str="ahoj";
preg_match($re,$str); //vrátí int(1), tedy shodu
V uvedeném regulárním výrazu jsou obsaženy jak bílé znaky (mezera), \n, \t, tak i text komentáře (#můj vlastní komentář), který bude zcela ignorován.
"Evaluate" - speciální modifikátor při nahrazování
Modifikátor se zkratkou "e" (odvozeno od "evaluate", anglicky "vyhodnotit") může být použit pouze v regulárních výrazech, které jsou argumentem funkce preg_replace()
(respektive jinde je jeho použití ignorováno). Použijeme-li tento modifikátor, řetězec obsahující "text náhrady" (v našich příkladech jsme pro něj používali proměnnou $replacement) bude vyhodnocen jako PHP kód. Použití si ukážeme na příkladu, kdy bude naším cílem převést všechny HTML tagy na malá písmena (pozor, pouze tagy, nikoli atributy).
$replacement="'\\1'.strtolower('\\2').'\\3'";
$str="<H1>Nadpis</H1>
<P>Text1</P>
<P>Text1</P>";
$result=preg_replace($re,$replacement,$str);
Výsledkem (obsahem proměnné $result) pak je HTML kód:
<p>Text1</p>
<p>Text1</p>
Všimněte si, že kromě modifikátoru "e" jsme použili i modifikátor "i" (case insensitive). Jak vidíte, modifikátory lze tedy kombinovat. Stačí je zapsat za sebou za koncový oddělovač / (na pořadí zápisu modifikátorů přitom nezáleží).
Regulárnímu výrazu v proměnné $re odpovídají otevírací i uzavírací (případně nepárové) HTML tagy (s i bez atributů). Výraz je složen ze tří subvýrazů. Prvnímu subvýrazu odpovídá < (otvírací tag) nebo </ (uzavírací tag). Druhému subvýrazu odpovídá sekvence znaků a-z (respektive A-Z, protože je použit modifikátor "i"), která představuje tag samotný. Třetímu subvýrazu odpovídá sekvence téměř libovolných znaků (vše kromě znaku >) následovaná znakem >.
Jak jste si asi všimli, tento příklad není nepodobný příkladu číslo 3 z předchozího článku. V tomto případě však zpracujeme řetězec představovaný zpětnou referencí na druhý subvýraz (\\2) pomocí PHP funkce strtolower()
, která převádí řetězec na malá písmena. Protože je nyní (kvůli modifikátoru "e") řetězec v proměnné $replacement vyhodnocován jako PHP kód, musí být zpětné reference \\1 a \\3 uzavřeny (jakožto řetězce) do jednoduchých uvozovek a spojeny s dalšími řetězci (respektive řetězcem vracejícím volání funkce strtolower('\\2')) pomocí běžného PHP operátoru pro spojování řetězců (. - tečka).
Kvantifikátory podruhé - "lenost" kontra "nenasytnost"
Již v prvním článku jsme si uvedli seznam všech kvantifikátorů a doposud jsme předpokládali, že se bude kvantifikátor snažit "pozřít" co možná nejdelší řetězec. Tedy například, když porovnáme řetězec abbb s regulárním výrazem ^a(b+), pak prvnímu subvýrazu bude odpovídat řetězec bbb. Daný regulární výraz by se samozřejmě "spokojil" (přesněji řečeno "by odpovídal") i s řetězcem ab, má-li však k dispozici delší řetězec, použije nejdelší možnou variantu, která ještě vede ke shodě. Proto říkáme, že kvantifikátory jsou standardně "nenasytné" (greedy).
Pomocí "ungreedy" modifikátoru (který má zkratku "U" a v PHP interní označení "PCRE_UNGREEDY") je možno přepnout chování kvantifikátorů z "nenasytného" na "líné" (lazy). Pokud se budou kvantifikátory chovat líně, bude se kvantifikátor snažit "pozřít" minimální počet znaků, které jsou třeba, aby řetězec odpovídal regulárnímu výrazu. Pokud použijeme (v "ungreedy" módu) opět řetězec abbb a regulární výraz ^a(b+), prvnímu subvýrazu bude odpovídat jednoznakový řetězec b. Zbytek řetězce bude ignorován (nepřehlédněte, že je použito pouze ukotvení za začátku pomocí ^ - vpravo od prvního výskytu b až do konce řetězce tak může být cokoli).
Modifikátor "U" zapne "líné" chování kvantifikátorů globálně pro celý výraz. Je však také možné, aby "zlenivěly" jen vybrané kvantifikátory v řetězci. Každý konkrétní kvantifikátor, který má "zlenivět", musí být bezprostředně následován otazníkem (?).
Místo kvantifikátorů ?, *, +, {m,n}, {m,} (kde m je minimální počet výskytů a n je maximální počet výskytů - více viz první článek), můžeme použít jejich líné varianty ??, *?, +?, {m,n}?, {m,}?.
Následující tabulka názorně ukazuje rozdíly v chování "nenasytných" a "líných" kvantifikátorů, respektive jaká část z modelového řetězce bbbbbb bude odpovídat (vytvářet shodu) jednotlivým regulárním výrazům.
Regulární výraz | Shoda |
---|---|
b? | b |
b?? | (prázdný řetězec) |
b* | bbbbbb |
b*? | (prázdný řetězec) |
b+ | bbbbbb |
b+? | b |
b{2, 4} | bbbb |
b{2, 4}? | bb |
b{3,} | bbbbbb |
b{3,}? | bbb |
b{5} | bbbbb |
Doplňme ještě, že pokud je pomocí modifikátoru "U" zapnuta globální "lenost", přidáním otazníku za konkrétní kvantifikátor se jeho (lokální) chování přepne na "nenasytné".
Perl-compatible regulární výrazy v PHP
Regulární výrazy jsou mocným nástrojem, který může výrazně zjednodušit a zpřehlednit kód programu. Nejčastěji je můžeme použít při kontrole či "parsování" vstupních dat. Tato série článků dosud nebyla ukončena!
- Perl-compatible regulární výrazy v PHP - modifikátory a líné kvantifikátory (právě čtete)
- Perl-compatible regulární výrazy v PHP - hranice
- Perl-compatible regulární výrazy v PHP - subvýrazy a zpětná reference
- Perl-compatible regulární výrazy v PHP - praktické příklady
- Perl-compatible regulární výrazy v PHP - základní konstrukce