Regulární výrazy
Obsah
Regulární výraz
Věřím, že spousta začínajících programátorů už tento termín zaslechla, a také věřím, že už si na něj zároveň stihla vytvořit patřičný podmíněný dávivý reflex. Myslím, že zbytečně. Přečíst regulár je často mnohem složitější, než jej napsat.
Regular expression, česky regulární nebo regulérní, chcete-li, výraz, můžeme přeložit jako výraz, který odpovídá nějakým pravidlům (regulím). Takový výraz je pak možné použít jako vzor pro nalezení odpovídajícího kusu textového řetězce.
Regulární výrazy jsou v AS obsaženy až od verze 3.0. Reprezentuje je objekt RegExp.
Syntaxe se shoduje se specifikací ECMA-262, starší brácha ActionScriptu - JavaScript - tedy obsahuje objekt téměř stejný.
Historicky je tento regulární výraz odvozen z Perlu.
var vyraz:RegExp = new RegExp('text'); vyraz = /text/; // ekvivalentní literál - všimněte si absence uvozovek
Regulární výraz je pak možné užít především ve čtveřici metod objektu String.
match(pattern:*):Array | Vrací pole nalezených kusů řetězce |
|---|---|
replace(pattern:*, repl:Object):String | Nahrazuje nalezené kusy řetězce |
search(pattern:*):int | Vrací index prvního nalezeného kusu řetězce |
split(delimiter:*, limit:Number):Array | Rozděluje řetězec na pole podle nalezených kusů |
'Práce s textem a regulární výrazy'.search(vyraz); // 8
Pravidla pro tvorbu regulárů
Byly popsány milionkrát. Po milion prvé se mi to psát nechce ale zároveň nechci odpálkovat čtenáře ke všem čertům. Co takhle kompromis - bleskový kurz?
Regulár je vzor
Okay jdem na to. Regulár je vzor, matrice nebo předloha, chcete-li. Interpret výrazu pak hledá kousek řetězce, který tomuto vzoru vyhovuje. Výraz /ahoj/ je taky regulární - bude vyhovovat sekvenci znaků 'ahoj'.
Obecné množiny a hranice
Častěji hledáme úsek podle obecnějšího vzoru - /a.oj/ vyhoví sekvenci 'ahoj', 'aXoj' nebo třeba 'a8oj', protože tečka je metaznak označující libovolný znak.
Metaznaky ^ (stříška) a $ (dolar) můžeme označit začátek a konec řetězce. Vzor /^ahoj/ bude nalezen v řetězci 'ahoj' ale už nikoliv v 'blabla ahoj'.
Vedle tečky existují i konkrétnější escape-metasekvence. Například \d pro číselný znak, \s pro libovolný bílý znak a tak dále. Rozhodně se neostýchejte pro zbytek nahlédnout do dokumentace.
Explicitní množiny
Výraz /regul[áé]rní/ pak obsahuje explicitní množinu znaků, také označovanou jako třídu. Bude vyhovovat sekvence 'regulární' i 'regulérní'. Pomlčkou lze automaticky stanovit rozsah některých skupin znaků - například /agent00[1-9]/ nebo /střelec na [a-e][1-8]/.
Stříška ^ na začátku množiny znamená její inverzi. /[^0-9]/ vyhoví jakémukoliv znaku, kromě číslice.
Kvantifikátory
Výraz můžeme zobecnit i co se délky týče. K tomu slouží kvantifikátory, které se píšou za daný znak a stanovují, kolikrát se může opakovat. * (hvězdička) označuje libovolný počet, + alespoň jednou a ? nejvýše jednou. Pro konkrétní počet pak slouží zápis {10} (právě desetkrát) nebo {5,10} (od pěti do deseti).
Pro výraz /aho+j/ bude vyhovovat sekvence 'ahoj' i 'ahoooooooooj'. Kvantifikátor je možné přiřadit i větší skupině, pro /(<br>)+/ bude vyhovovat '<br>' stejně jako '<br><br><br>'.
Disjunkce
Znak | (pipe) funguje jako logické nebo, takže můžete psát /vážen(ý|á) pa(ne|ní)/ a bude vyhovovat 'vážený pane' i 'vážená paní'.
Rozhlédnutí (lookahead)
Text je obecně v reguláru porovnáván po znacích zleva doprava. Konstrukce lookahead slouží k nahlédnutí dopředu. Například pokud má (nebo nesmí) po aktuálním znaku následovat nějaká konkrétní sekvence.
Obecně má konstrukce tvar (?=vnořený výraz) respektive (?!vnořený výraz) pro pozitivní respektive negativní lookahead.
Výraz /[.,?!](?!</p>)/ bude hledat interpunkční znaménka, po kterých bezprostředně nenásleduje konec odstavce.
Nenasytnost a lenost (lazy quantification)
Obecnou vlastností interpreta regulárních výrazů je nenasytnost. Ze všech vyhovujících sekvencí vybere vždy tu nejdelší. Zvláště u vyhledávání vnitřků čehokoliv (HTML tagů typicky) je to na pěst - místo vnitřku dostanete všechno od prvního do posledního tagu.
Některé jazyky znají přepínač ungreedy, zde nám tato vymoženost dopřána není, nicméně můžeme použít líný kvantifikátor. Jde o připojení dalšího kvantifikátoru ? (nejvýše jednou) k tomu původnímu.
Pro /a.+/ vyhoví celý řetězec 'auuuuuuu', ale /a.+?/ se spokojí už s prvními dvěma znaky.
Přepínače
Pěti přepínači můžete ovlivnit obecné chování interpreta.
g (global) pro vrácení více než jednoho výsledku u metody match(), i (ignoreCase) pro ignorování velikosti písmen (což ovšem u některých diakritických znaků nefunguje spolehlivě), m (multiline) pro víceřádkový režim, kdy $ a ^ bude vyhovovat i pro začátek a konec řádku, s (dotall), při kterém bude množina . (tečka) vyhovovat i novému řádku, a konečně x (extended) pro ignorování mezer ve výrazu, který pak jde napsat víc přehledně.
var vyraz:RegExp = new RegExp('text', 'gimsx'); vyraz = /text/gimsx; // přepínače jsou vně výrazu
Použití skupin pro zpětné reference
Při nahrazování textu pomocí regulárních výrazů často potřebujeme použít i původní části nalezeného řetězce. Na takové části se můžeme odkázat zápisem $n (kde n označuje číslo bloku ohraničeného kulatou závorkou).
var html:String = 'text, který je <b class="cerveny">tučně</b>.'; html.replace(/<b(.*?)>(.+?)<\/b>/,'<strong$1>$2</strong>'); // text, který je <strong class="cerveny">tučně</strong>.
I v samotném regulárním výrazu je možné zpětnou referecni použít. V takovém případě se její číslo uvozuje zpětným lomítkem. Výraz /<([a-z]+)>(.+?)<\/\1>/ by hledal párové tagy bez atributů.
Nezachycovaná skupina
Všechny uzávorkované skupiny jsou k dispozici ve zpětných referencích. To může být zdrojem celkem kvalitního bordelu, především pokud používáte hodně skupin jen pro vymezení alternujících nebo opakovaných sekvencí.
Skupina uvozená ?: nebude zahrnuta do referencí. Například /Vážen[ýá] (?:pane|paní)/.
Metody objektu RegExp
Také samotný objekt RegExp má své metody. Používají se méně než metody objektu String, ale nabízí některé zajímavé možnosti použití výrazu.
Dvě následující metody by se daly považovat za reverzní k metodám match nebo search objektu String.
exec(str:String):Object | Vyhledává vyhovující sekvence předaného řetězce. |
|---|---|
test(str:String):Boolean | Zjišťuje, jestli předaný řetězec vyhovuje výrazu. |
var re:RegExp = /<([a-z]+)>(.+?)<\/\1>/; var obj:Object = re.exec('Text psaný <i>kurzívou</i> a <b>tučně</b>.');

Návratovou hodnotou metody exec je objekt obsahující výsledky porovnání.
Jak vidíte na obrázku, nalezený řetězec je v indexu nula, následují jeho části vymezené skupinami, index (pozice nalezeného řetězce) a další vlastnosti.
Jak vidíte, byl nalezen jen první tag. Pokud výraz obsahuje přepínač g (global), je možné opakovaným voláním metody exec vyhledat všechny výskyty. Interpret se pak řídí metodou lastIndex našeho objektu RegExp.
Pojmenované skupiny
Na závěr ještě proprietární blbůstka, nefungující už v ostatních ECMA jazycích. Skupině je možné ve Flashi přiřadit jméno zápisem (?P<jmeno>vyraz).
var re:RegExp = /(?P<day>[0-9]{2})-(?P<month>[0-9]{2})-(?P<year>[0-9]{4})/; re.exec('25-06-2010').year; // 2010
Ve vráceném objektu je pak nalezená část k dispozici pod stejnojmenou vlastností.