Navigace

Hlavnφ menu

 

Perl-compatible regulßrnφ v²razy v PHP - specißlnφ typy uzßvorkovßnφ

KulatΘ zßvorky jsme doposud pou₧φvali pro ohraniΦenφ subv²raz∙, a to bu∩ proto, ₧e jsme cht∞li subv²raz doplnit kvantifikßtorem, nebo proto, ₧e jsme se na °et∞zec odpovφdajφcφ subv²razu cht∞li odkazovat pomocφ zp∞tnΘ reference. KulatΘ zßvorky se ale v Perl-compatible regulßrnφch v²razech pou₧φvajφ takΘ k sestavenφ specißlnφch konstrukcφ, kterΘ ovliv≥ujφ chovßnφ regulßrnφho v²razu.

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

Uzßvorkovßnφ netvo°φcφ zp∞tnΘ reference

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.

PojmenovanΘ subv²razy

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 (?P<jmeno>v²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<rok>(?:19|20)[0-9]{2})-(?P<mesic>[0-9]{2})-(?P<den>[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<rok>(?:19|20)[0-9]{2}) je slo₧en z pojmenovßnφ subv²razu ?P<rok>, 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<mesic>[0-9]{2}) se sklßdß op∞t z pojmenovßnφ subv²razu ?P<mesic>, 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<rok>(?:19|20)[0-9]{2})-(?P<mesic>0[1-9]|1[0-2])-(?P<den>0[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.

Komentß°e

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 ).

Pecka, Miroslav (6. 4. 2005)