Perl-compatible regulární výrazy v PHP – modifikátory a líné kvantifikátory

22. března 2005

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:

  1. 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 \.
  2. Čá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:

$re=“/^ ah\n\toj$#můj vlastní komentář/x“;
$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).

$re=“/(<\/?)([a-z]+)([^>]*>)/ei“;
$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:

<h1>Nadpis</h1>
<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é“.

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

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

Předchozí článek Ovládací prvok CAPTCHA v ASP.NET
Další článek SUN Java Studio Creator
Štítky: Články

Mohlo by vás také zajímat

Nejnovější

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *