Perl-compatible regulární výrazy v PHP – hranice

10. března 2005

Funkčnost regulárních výrazů rozšiřují také takzvané modifikátory, které upravují způsob vyhodnocování regulárního výrazu. Právě modifikátory mohou změnit význam některých metaznaků. Kromě modifikátorů probereme v tomto článku také několik nových konstrukcích pro ukotvování řetězce (nebo jeho částí).

Modifikátory – první přiblížení

Jak jste si jistě všimli, při zpracování regulárních výrazů jsou rozlišována malá a velká písmena, a tak regulárnímu výrazu [a-z]+ řetězec Ahoj odpovídat nebude. Samozřejmě můžeme upravit regulární výraz na [a-zA-Z]+ a pak již ke shodě dojde. Praktičtější by však bylo nějak zajistit, aby regulární výrazy (respektive porovnávání pomocí nich) nerozlišovaly malá a velká písmena. To je možno zařídit pomocí takzvaného „case insensitive“ (někdy též „caseless“, v PHP s interním označením „PCRE_CASELESS“) modifikátoru.

Modifikátor (modifier) je obecně příznak, který v určitém smyslu mění chování při vyhodnocování regulárního výrazu – například zajistí nerozlišování malých a velkých písmen. Každý modifikátor má svou jednopísmennou zkratku, která se zapíše za koncový oddělovač (delimiter) regulárního výrazu (v našich příkladech používáme jako oddělovač lomítko). Pro „case insensitive“ jde o zkratku „i“. Volání funkce preg_match("/^[a-z]+$/i","Ahoj") tak vrátí 1, což signalizuje, že řetězec regulárnímu výrazu (s použitým modifikátorem „i“) odpovídá.

Máme za sebou první a asi nejjednodušší modifikátor. K dalším již ne tak triviálním modifikátorům se dopracujeme záhy (například už v souvislosti s „hranicemi“).

Hranice aneb shody nulové délky

Hranice (chcete-li meze, či rozmezí) odpovídají určité pozici v textu, který pak jako celek odpovídá regulárnímu výrazu. Již v úvodním článku jsme ukázali možnost označení začátku (respektive konce) řetězce pomocí metaznaku ^ (respektive $). Znaky označující hranice vytvářejí takzvané „shody nulové délky“ (zero-lenght matches), protože znaku označujícímu hranici (například ^ či $) neodpovídají žádné znaky porovnávaného řetězce, ale pouze určitá pozice v tomto řetězci. Tuto pozici si můžeme pro názornost představit třeba jako kurzor blikající v textovém editoru na místě, kde budou psány nové znaky.

Hranice slova

Hranice slova jsou další konstrukcí regulárních výrazů, která vytváří shody nulové délky. Můžeme také říci, že jakákoli hranice obsažená v regulárním výrazu „ukotví“ část výrazu před či za hranicí na určité místo. Za hranici slova je považováno místo:

  • mezi jakýmikoli dvěma znaky z nichž jeden je znak „slova“ (\w) a druhý není znak „slova“ (\W)
  • na začátku řetězce, pokud prvním znakem je znak „slova“ (\w)
  • na konci řetězce, pokud posledním znakem je znak „slova“ (\w)

Nesmíme zapomenout, že znak „slova“ (word character) může obsahovat i číslice a podtržítko (viz úvodní článek). Hranice slova se označuje pomocí \b. Regulárnímu výrazu ^a\b.+\bz$ tak bude odpovídat například řetězec a bbb z, ale také řetězec a z. V obou případech bude první hranici slova odpovídat pozice za znakem a a druhé hranici slova pozice před znakem z. V prvním případě bude části výrazu .+ odpovídat mezera ( ), v druhém případě sekvence  bb  (mezera, dva znaky b, mezera).

Kromě hranice slova existuje také její opak, označovaný pomocí \B. Jedná se o přesnou negaci, a tak vytváří shodu nulové délky na všech místech, kde ji \b nevytváří. To jest:

  • mezi jakýmikoli dvěma znaky, pokud oba tyto znaky jsou znaky „slova“ (\w) nebo oba tyto znaky nejsou znaky „slova“ (\W)
  • na začátku řetězce, pokud prvním znakem není znak „slova“ (\W)
  • na konci řetězce, pokud posledním znakem není znak „slova“ (\W)

Začátky a konce řádku

Pokud text, který chceme pomocí regulárního výrazu zpracovat, má více řádků, určitě se bude hodit označit hranice jednotlivých řádků. Člověk chápe pojem „řádek“ intuitivně, pro počítač to však je sekvence znaků:

  • které bezprostředně předchází i po ní bezprostředně následuje znak konce řádku \n (ASCII znak 10)
  • která začíná prvním znakem řetězce a po ní bezprostředně následuje znak konce řádku \n
  • které bezprostředně předchází znak konce řádku \n a která končí posledním znakem řetězce

Za jistých okolností mohou být schopnosti metaznaků ^ a $ rozšířeny. Potom metaznak ^ vytváří shodu nulové délky nejen na začátku řetězce, ale i na začátku každého řádku, a metaznak $ vytváří shodu nulové délky na konci každého řádku. Abychom zajistili takové chování, musíme použít takzvaný „multiple lines“ (případně též „multiline“, v PHP s interním označením „PCRE_MULTILINE“) modifikátor, který má zkratku „m“. Použití „multiple lines“ módu předvedu na modelovém příkladu. Předpokládejme, že v proměnné $str je seznam kladných čísel, přičemž každé číslo je na jednom řádku. A naším úkolem je nahradit čísla dělitelná beze zbytku deseti (tedy čísla končící nulou) číslem jedna.

$re=“/^\d+0$/m“;
$str=“1505\n5050\n70808\n909″;
$replacement=“1″;
$result=preg_replace($re,$replacement,$str);

Výsledkem (v proměnné $result) pak bude:

1505
1
70808
909

Řetězec v proměnné $str představuje čtyřřádkový text. Protože v proměnné $re za koncovým oddělovačem / následuje modifikátor m, metaznaky ^ a $ umožňují shodu na začátku a konci řádku, výraz \d+0 je tak zleva ukotven k začátku řádku a zprava ke konci řádku. Z toho plyne, že řetězec, který má regulárnímu výrazu odpovídat, musí mít jako poslední znak nulu a všechny ostatní (předcházející) znaky musí odpovídat skupině znaků \d (číslice 0-9).

Jednoznačný začátek a konec řetězce

Jak jsme si ukázali, při zapnutém „multiple lines“ módu, mohou metaznaky ^ a $ vytvářet shodu nejen na začátku a konci řetězce. Existuje však možnost, jak označit výhradně začátek (respektive výhradně konec) řetězce i při zapnutém „multiple lines“ módu. Hranice označující vždy začátek řetězce se zapisuje jako \A a hranice vždy označující konec řetězce jako \Z. Sekvence \A vytváří shodu nulové délky před prvním znakem řetězce. Sekvence \Z vytváří shodu nulové délky za posledním znakem řetězce (případně za předposledním znakem za předpokladu, že posledním znakem je \n). Sekvence \z (tentokrát s malým „z“) vytváří shodu nulové délky vždy pouze za posledním znakem řetězce (i když posledním znakem je \n).

Hranice – shrnutí

Shrňme si na závěr různé typy hranic a jejich chování pří zapnutém či vypnutém „multiple lines“ módu.

Hranice Bez „multiple lines“ S „multiple lines“
^ začátek řetězce začátek řetězce, začátek řádku
$ konec řetězce 2) konec řetězce 1), konec řádku
\A začátek řetězce začátek řetězce
\Z konec řetězce 1) konec řetězce 1)
\z konec řetězce konec řetězce
\b hranice slova hranice slova

1) vytváří shodu na úplném konci řetězce nebo před posledním znakem řetězce, pokud je posledním znakem \n

2) vytváří shodu na úplném konci řetězce nebo (pokud není aktivován modifikátor „D“ – „dollar endonly“) před posledním znakem řetězce, pokud je posledním znakem \n

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 expresfoto.cz
Další článek skolnistranky.cz
Š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 *