Perl-compatible regulární výrazy v PHP (6) – speciální typy uzávorkování

Mezi tyto konstrukce patří:

  • uzávorkování netvořící zpětné reference (non-capturing parentheses)
  • pojmenované subvýrazy (named subpatterns), respektive pojmenované zpětné reference
  • komentáře (další možnost jejich zápisu)
  • modifikátory (další možnost jejich zápisu)
  • „look ahead assetions“ a „look behind assertions“ (což můžeme v tomto kontextu přeložit asi jako „tvrzení o následujícím“ a „tvrzení o předcházejícím“)
  • podmíněné subvýrazy

Pokud použijeme například regulární výraz ^a(bc)+d$, budeme moci využít zpětnou referenci na první (jediný) subvýraz. Jestliže však víme, že zpětnou referenci nebudeme potřebovat, ale přesto potřebujeme určit opakování určité sekvence znaků (v našem případě bc následované kvantifikátorem +), pak můžeme použít takzvané uzávorkování netvořící zpětné reference (non-capturing parentheses).

Pokud použijeme regulární výraz ^a(?:bc)+d$, sekvence ?: za levou kulatou závorkou zajistí, že na řetězec (bc) odpovídající výrazu v těchto závorkách se nebude možno odkazovat pomocí zpětné reference. Použití „uzávorkování netvořícího zpětné reference“ má dvě výhody. Jednak si počítač při zpracování regulárního výrazu ušetří práci (respektive místo v paměti), když si nebude muset pamatovat zpětné reference, jednak se tímto způsobem může zpřehlednit práce se zpětnými referencemi v složitém regulárním výrazu.

Ve složitějším regulárním výrazu můžeme mít mnoho subvýrazů, které tvoří zpětnou referenci. Pak nemusí být snadné se v očíslování jednotlivých subvýrazů vyznat. Krom toho se může stát, že na začátku regulárního doplníte později další subvýraz a všechny subvýrazy (vpravo od něj) se tím přečíslují. Vhodné proto je jednotlivé subvýrazy pojmenovat vlastním označením (můžeme použít alfanumerické znaky a podtržítko).

Takzvané pojmenované subvýrazy (named subpatterns) můžeme využít při použití funkce preg_match() ve tvaru preg_match($re,$str,$matched), kde $matched je pole řetězců, které odpovídají jednotlivým subvýrazům. Toto pole je (jak jsme si řekli již dříve) standardně indexováno čísly jednotlivých subvýrazů. Pokud však některé subvýrazy pojmenujeme, bude pole obsahovat i prvky s indexy odpovídajícími těmto pojmenováním. Pro pojmenování subvýrazu se používá konstrukce (?Pvýraz).

Podívejme se na modelový příklad, v němž máme za úkol otestovat, zda zadaný řetězec (datum) odpovídá formátu RRRR-MM-DD (přičemž první dvojčíslí roku smí být pouze 19 nebo 20), a pokud odpovídá, zobrazit jednotlivé části data (den, měsíc, rok).

$re=“/^(?P(?:19|20)[0-9]{2})-(?P[0-9]{2})-(?P[0-9]{2})$/“;

$str=“2005-07-12″;

$result=preg_match($re,$str,$matched);

if($result) //zadaný řetězec regulárnímu výrazu odpovídá

{

echo „Den: „.$matched[„den“].“\n“;

echo „Měsíc: „.$matched[„mesic“].“\n“;

echo „Rok: „.$matched[„rok“].“\n“;

}

else //zadaný řetězec regulárnímu výrazu neodpovídá

{

echo „Špatný formát data.“;

};

Rozeberme si nejdříve samotný regulární výraz. Tento výraz je složen ze tří subvýrazů (pro rok, měsíc a den) tvořících zpětné reference, které jsou odděleny obyčejným znakem pomlčky. První subvýraz (?P(?:19|20)[0-9]{2}) je složen z pojmenování subvýrazu ?P, dále z uzávorkování netvořícího zpětnou referenci (?:19|20) a nakonec ze skupiny znaků [0-9] následované kvantifikátorem {2} (poslední dvojčíslí roku). Druhý subvýraz (?P[0-9]{2}) se skládá opět z pojmenování subvýrazu ?P, za nímž následuje samotný výraz [0-9]{2} popisující dvojciferné číslo. Třetí subvýraz je s druhým až na pojmenování shodný.

Výše uvedený regulární výraz není zcela dokonalý, záměrně jsem jej pro účely demonstrace probíraných principů zjednodušil. Regulárnímu výrazu [0-9]{2} totiž například odpovídá i sekvence znaků 00. Krom toho regulární výraz má popisovat měsíc (respektive den v měsíci), takže například číslo 56 by také nemělo být považováno za správný vstup. Dokonalejším řešením jistě bude výraz ^(?P(?:19|20)[0-9]{2})-(?P0[1-9]|1[0-2])-(?P0[1-9]|[12][0-9]|3[01])$. Zde je pro popis měsíce použito 0[1-9]|1[0-2] (místo původního [0-9]{2}) a pro popis dne v měsíci 0[1-9]|[12][0-9]|3[01] (místo původního [0-9]{2}).

Vraťme se nyní ještě na skok k poli $matched, které obsahuje řetězce odpovídající jednotlivým subvýrazům, a podívejme se, co ve skutečnosti v našem příkladu obsahuje. K zobrazení obsahu pole jsme použili příkaz var_dump($matched).

array(7) {

[0]=>

string(10) „2004-07-12“

[„rok“]=>

string(4) „2004“

[1]=>

string(4) „2004“

[„mesic“]=>

string(2) „07“

[2]=>

string(2) „07“

[„den“]=>

string(2) „12“

[3]=>

string(2) „12“

}

Jak vidíme, pole nemá čtyři prvky, jak bychom mohli očekávat, ale sedm prvků. Pokud totiž použijeme pojmenované subvýrazy, hodnota odpovídající subvýrazu se do pole uloží dvakrát. Jednou s indexem odpovídajícím číslu subvýrazu, podruhé s indexem (klíčem) odpovídajícím pojmenování subvýrazu.

Pokud máme složitější regulární výraz, můžeme do něj (i na několik míst) vložit vysvětlující komentáře. Jedna možnost, jak přidat komentáře, byla popsána v předchozím článku (použití modifikátoru „extended“). Druhou možností je vložení speciální konstrukce ve tvaru (?#komentář) do regulárního výrazu. Regulárnímu výrazu ^a(?#můj komentář)b$ tak bude vyhovovat právě a pouze řetězec ab, protože za komentář se považují všechny znaky mezi (?# a ).

Tento článek byl původně publikován na serveru Interval.cz, kde naleznete
originální verzi článku.
Miroslav Pecka

Share
Published by
Miroslav Pecka
Tags: phpregexp

Recent Posts

GA4 (not set) problém & jeho řešení

Jak se zbavit (not set) v Session Source a Session Medium?

2 roky ago

Měření QR kódů a offline zdrojů do Google Analytics

Chcete doměřit efekt vaší offline reklamy, ze které vedete lidi na váš web? Jde to…

2 roky ago

5+1 věcí, které se online markeťák může naučit od ajťáka

Tenhle článek jsem měl rozepsaný fakt dlouho, ale je stále aktuální… Trápí mě, že opakovaně…

4 roky ago

Profesionál v onlinu: řemeslo + kontext + přesahy

Poslední dobou jsem se setkal s pár majiteli malých firem, kteří mají web a snaží…

4 roky ago

Nástroje pro tvorbu screencast videí

Občas se mě někdo ptá, co používám pro tvorbu screencastů a online videí. Které nástroje…

4 roky ago

7 Google Analytics video návodů pro efektivnější práci

V rámci 5 videí najdete 7 krátkých video tipů pro zefektivnění práce s Google Analytics…

5 roky ago