Regulární výrazy Honza Vrbata
[email protected]
CO TO JE ? ●
●
●
●
●
Regulární výraz (regular expression) je speciálně zkonstruovaný řetězec popisující celou množinu řetězců, konkrétně regulární jazyk. Prakticky se používají na vyhledávání a nahrazování v textech.
Teoreticky zpracováno v teorii formálních jazyků pány McCullochem, Pittsem a Kleenem kolem roku 1940. Pojem formální jazyk označuje množinu konečných slov (tj. slov konečné délky) nad určitou abecedou Příkladem abecedy je např. {a,b,c}, slovem nad touto abecedou je aabca, accbaa, … Regulární jazyk je formální jazyk, jehož slova lze rozpoznat tak, že při načtení každého písmene se provede změna stavu v závislosti na předchozím stavu a přečteném písmenu. Pokud je výsledkem přečtení celého slova tzv. koncový stav, patří slovo do jazyka. Vlastní algoritmus zpracování bývá realizován tzv. konečným stavovým automatem (finite state machine).
KONEČNÝ STAVOVÝ AUTOMAT KSA je teoretický výpočetní model používaný v informatice pro studium vyčíslitelnosti a obecně formálních jazyků. Popisuje velice jednoduchý počítač, který může být v jednom z několika stavů, mezi kterými přechází na základě symbolů, které čte ze vstupu. Množina stavů je konečná, konečný automat nemá žádnou další paměť kromě informace o aktuálním stavu. S je konečná množina stavů. ● Σ je konečná množina vstupních symbolů, nazývaná abeceda. ● σ je tzv. přechodová funkce (též přechodová tabulka), popisující pravidla přechodů mezi stavy. Může mít buď podobu S × Σ → S (deterministický automat), nebo S × {Σ ∪ ε} → P(S) (nedeterministický automat). ● s je počáteční stav, s ∈ S. ● A je množina přijímajících (konečných) stavů, A ⊆ S. ●
KONEČNÝ STAVOVÝ AUTOMAT Znázornění konečného stavového automatu : (Příklad: testuje dělitelnost dvojkového čísla třemi)
S = (S0, S1, S2) Σ = (0, 1) s = S0 A = {S0}
… množina stavů … abeceda … počáteční stav … přijímací stavy
REGULÁRNÍ VÝRAZY Používané dialekty : ●
●
POSIX (POSIX 1003.2) - BASIC - MODERN (extended) PCRE - Perl Compatible Regular Expressions (http://www.pcre.org/) Aplikace : Jednoúčelové vyhledávací nástroje jako grep, egrep, fgrep, atd. ● Interaktivní a neinteraktivní editory jako ed, vi, sed, atd. ● Implementace v programovacích jazycích jako awk, PERL, PHP, JavaScript, JAVA, PYTHON, .NET, atd. ● Implementace v aplikačních programech jako www server Apache, poštovní server Postfix, atd. ●
REGULÁRNÍ VÝRAZY Typy regulárních strojů : ●
●
●
Traditional NFA (klasický nedeterministický) sed, grep, less, Java, .NET, PCRE, Perl, Python, Ruby, atd. Posix NFA (nedeterministický podle POSIX) mawk, lex DFA (deterministický) GNU grep/egrep, GNU awk, Tcl
REGULÁRNÍ VÝRAZY Literatura a další studijní materiály : ●
●
●
Mastering Regular Expressions, Jeffrey E. F. Friedl, O'Relly Media
Elektronický seriál Pavla Satrapy http://www.kit.vslib.cz/%7Esatrapa/docs/regvyr/ Elektronická učebnice http://www.regexp.info/
LITERÁLY Literál (literal) : Literál je jeden libovolný znak. Jako alfanumerické znaky chápeme velká a malá písmena anglické abecedy a národních abeced. Ostatní znaky jako interpunkční znaménka a další speciální znaky označme jako nealfanumerické znaky. Příklad použití : Regulárnímu výrazu a (jeden literál) vyhoví jakýkoli řetězec, který daný literál obsahuje na jakémkoli místě, např.: a, abbc, ccxa, rracc, atd.
LITERÁLY Předpoklad : Jakýkoli alfanumerický znak reprezentuje vždy uvedený znak. Jakýkoli nealfanumerický znak má v regulárním výrazu speciální vlastnost. Tuto vlastnost lze potlačit pomocí escape sekvence (je to skupina znaků uvozených zpětným lomítkem, která se celá vyhodnotí jako jeden literál) : \. reprezentuje znak . \* reprezentuje znak * \\ reprezentuje znak \
Zápisem zpětného lomítka před alfanumerický znak je možné naopak aktivovat nějakou speciální vlastnost !!!!
ESCAPE SEKVENCE Escape sekvence (character shorthands) : \a \b \e \f \n \r \t \v
alert backspace escape form feed newline carriage return horizontal tab vertical tab
\num \xnum \unum
octal escape hex escape unicode escape
007 010 033 014 012 015 011 013
Pozn.: ASCII hodnoty jsou uvedeny oktalově.
(na MacOS 015)
METAZNAKY Metaznaky (metacharacters) : Existuje celkem 12 metaznaků. Metaznak je znak z kategorie nealfanumerických znaků, který má v regulárním výrazu speciální funkci či vlastnost. Speciální vlastnost je možné potlačit pomocí escape sekvence (zpětné lomítko). Metaznaky : \, |, (, ), ^, $, [, ., *, +, ?, { Poznámka : Ostatní nealfanumerické znaky žádné speciální významy nemají ! Není tedy nutné je uvozovat zpětným lomítkem !! Pokud to ale uděláme, nic tím nezkazíme :-) To je dobré pravidlo pro začátek. Jinak řečeno tedy předpokládáme, že alfanumerické znaky používáme v jejich běžném významu, zatímco u nealfanumerických automaticky předpokládáme nějakou speciální vlastnost. Zpětné lomítko používáme na zapnutí resp. vypnutí této speciální funkce !
ZŘETĚZENÍ LITERÁLŮ Zřetězení znaků : Zřetězení je operace spojení jednotlivých znaků do jednoho celku, jedné skupiny znaků (literálů). Příklad použití : Regulárnímu výrazu abc (zřetězení znaků) vyhoví jakýkoli řetězec, který obsahuje uvedenou skupinu znaků na jakémkoli místě, např.: abc, abcx, ccxabc, rrabcdcc, atd.
Libovolný znak Libovolný znak (dot) : Metaznaku . v regulárním výrazu vyhoví jeden libovolný znak ve zkoumaném řetězci. Příklad použití : Regulárnímu výrazu a.c vyhoví jakýkoli řetězec, který obsahuje skupinu tří znaků např.: abc, axc, arcx, ccxa*c, rra&cdcc, atd.
VÝČET ZNAKŮ Výčet znaků (list of characters) : Skupina znaků je posloupnost znaků bez oddělovačů uzavřená v hranatých závorkách. Celé této skupině vyhoví právě jeden znak z této skupiny.
Příklad použití : Regulárnímu výrazu gymná[sz]ium vyhoví například tyto řetězce : gymnázium, gymnásium, atd.
VÝČET ZNAKŮ Výčet znaků (list of characters) : V hranatých závorkách se uplatní pouze dva metaznaky : - interval ^ negace Příklad použití : Jednu číslici desítkové soustavy lze popsat regulárním výrazem [0123456789] ● Efektivněji to lze zapsat takto [0-9] ● Jedno malé písmeno anglické abecedy [abcdefghijklmnopqrstuvwxyz] ● Efektivněji to lze zapsat takto [a-z] ● Jedno malé nebo velké písmeno anglické abecedy nebo desítková číslice [a-zA-Z0-9] ● Jedno malé písmeno české abecedy [a-zěščřžýáíéťďóň] ●
VÝČET ZNAKŮ Výčet znaků (list of characters) : Operátor intervalu – musí mít definovány obě strany intervalu !!! Operátor negace ^ musí být uveden hned po levé hranaté závorce jinak ztratí svůj speciální význam !!!
Příklad použití : Jakýkoli jiný znak než malé a [^a] ● Jakýkoli jeden znak vyjma číslice desítkové soustavy [^0-9] ● Něco jiného než malé písmeno anglické abecedy [^a-z] ●
TŘÍDY ZNAKŮ Třídy znaků (character class) : Výčtem
POSIX
PCRE
[0-9]
[[:digit:]]
\d
[^0-9]
[^[:digit:]]
\D
[a-zA-Z0-9_] [a-zA-Z0-9_] [:alnum:] [[:alnum:]]
\w
[^a-zA-Z0-9_] [^[:alnum:]]
\W
[a-z]
[[:alpha:]]
Poznámka : Do třídy znaků jako [:alpha:] mohou patřit i znaky národních abeced !!! Záleží na nastavení lokalizace systému, kde regulární výrazy používáme.
TŘÍDY ZNAKŮ POSIX třídy znaků : [:alnum:] [:alpha:] [:blank:] [:digit:] [:lower:] [:space:] [:puntct:] [:upper:] [:xdigit:]
písmena a číslice písmena mezera a tabelátor číslice malá písmena bílé znaky interpunkční znaky velká písmena hexadecimální číslice
TŘÍDY ZNAKŮ Ekvivalenty znaků (character equivalents) : Některé implementace národních prostředí definují ekvivalenty znaků. Například ekvivalentní třída n může obsahovat znaky n a ñ, nebo třída a může obsahovat znaky a, à nebo á. Ekvivalentní třída se pak zapisuje takto : [=n=] nebo [=a=], atp.
KVANTIFIKÁTORY (opakování) Kvantifikátory (quantifiers) : Kvantifikátory slouží ke kontrole počtu opakování. Základním kvantifikátorem je *. Kvantifikátor se vždy týká bezprostředně předcházejícího literálu v regulárním výrazu. Hvězdička značí, že daný znak se v řetězci může vyskytovat v libovolném počtu, tedy i v nulovém ! Příklad použití : Libovolný počet znaku a i nulový počet výskytů a* ● Alespoň jeden znak a aa* ● Regulárnímu výrazu ab*c vyhoví skupina znaků, která začíná znakem a, končí znakem c a mezi nimi obsahuje libovolný počet znaků b, např.: ac, abc, abbbbbbbc, ... ●
KVANTIFIKÁTORY (opakování) Kvantifikátory (quantifiers) : Kvantifikátory slouží ke kontrole počtu opakování. Dalším kvantifikátorem je +. Kvantifikátor se vždy týká bezprostředně předcházejícího literálu v regulárním výrazu. Plus značí, že daný znak se v řetězci musí vyskytovat alespoň jednou. Příklad použití : Alespoň jeden znak a a+ ● Regulárnímu výrazu ab+c vyhoví skupina znaků, která začíná znakem a, končí znakem c a mezi nimi obsahuje alespoň jeden znak b, např.: abc, abbbbbbbc, ... ●
KVANTIFIKÁTORY (opakování) Kvantifikátory (quantifiers) : Kvantifikátory slouží ke kontrole počtu opakování. Dalším kvantifikátorem je ?. Kvantifikátor se vždy týká bezprostředně předcházejícího literálu v regulárním výrazu. Otazník značí, že daný znak se v řetězci musí vyskytovat nejvýše jednou. Příklad použití : Nejvýše jeden znak a a? ● Regulárnímu výrazu ab?c vyhoví skupina znaků, která začíná znakem a, končí znakem c a mezi nimi obsahuje nejvýše jeden znak b : ac, abc ●
MECHANISMUS SROVNÁVÁNÍ Backtracking - hladovost (greediness) :
Poznámka : Implicitně se všechny kvantifikátory chovají hladově !
KVANTIFIKÁRORY - syté verze Hladovost H kvantifikátorů *,+,? lze eliminovat použitím modifikátoru ? : l a Greediness Laziness d * *? o + +? v ? ?? o s t Příklad použití : Rozdíl mezi .*.*, .*?.* a .*.*? ● Příklad na minulé straně ●
KVANTIFIKÁRORY Kvantifikátory (přesný počet opakování) : H Kromě obecných kvantifikátorů *,+,? existuje možnost přesného l počtu a opakování pomocí konstrukce se složenými závorkami. Kvantifikátor se vždy týká bezprostředně předcházejícího znaku d v regulárním výrazu. o v Regulární výraz Počet opakování o {k} n=k s {min,max} min≤n≤max t {min,} min≤n {0,max} n≤max Pozn.: Tento kvantifikátor bez horní meze {min,} se chová hladově. Lze opět modifikovat pomocí modifikátoru ?, tedy takto {min,}?
Příklad použití : ●
Rodné číslo [0-9]{2}[0156][0-9][0-3][0-9][ \/][0-9]{3,4}
VARIANTY Varianty (alternatives) :
H l Operátor varianty | umožňuje provádět v regulárním výrazu a operaci OR. Jeho platnost je až na hranici nejvnitřnějších kulatých závorek d na celý vzor, pokud nejsou závorky použity. nebo o v o Příklad použití : s t ● Kočka nebo pes kočka|pes Výrazu aaa|bbb|ccc odpovídají řetězce aaa nebo bbb nebo ccc ● Výrazu aaa|b|c odpovídají řetězce aaa nebo b nebo c ● Výrazu aa(a|b|c) odpovídají řetězce aaa nebo aab nebo aac ● Pozor na prioritu Veselé Vánoce|Velikonoce. Vyhoví řetězec Veselé Vánoce nebo řetězec Velikonoce, protože operace zřetězení má větší prioritu než operace alternativy !!! ● Regulární výraz pro testování dne v měsíci (číslice 1-31) 0?[1-9]|[12][0-9]|3[01] ●
VARIANTY Varianty (alternatives) :
H l Je-li v jednom okamžiku možné provádět porovnání s více variantami, a provádí se toto porovnání vždy zleva. Proto záleží na pořadí v jakém d jednotlivé varianty uvedeme. o v o Zkoumaný text aaabbbccc : s ● tregulárnímu výrazu b+|b+c+ vyhovuje bbb ●
regulárnímu výrazu b+c+|b+ vyhovuje bbbccc
Je nalezena vždy ta varianta, která je na prvním místě, i když je možné ve stejném řetězci nalézt varianty obě.
SESKUPOVÁNÍ H l Seskupování (parentheses) : a dOperátor kulatých závorek () umožňuje vytvářet seskupení pro ozměnu priorit, platnost kvantifikátorů, zpětné reference, atd. v o s Příklad použití : t ● Příklad s variantami Veselé (Vánoce|Velikonoce) ● Příklad s kvantifikátorem a(bc)+d
SESKUPOVÁNÍ H Seskupování (parentheses) - zpětné reference: l a Operátor kulatých závorek () umožňuje vytvářet seskupení pro d změnu priorit, platnost kvantifikátorů, zpětné reference, atd. Dochází o kvzapamatování částí řetězce, které odpovídají regulárním podvýrazům. Reference na ně je možné provádět pomocí metasymbolů \1, \2, atd. o s t Příklad použití : Nalezení pětiznakových palindromů (.)(.).\2\1 ● Zápis data ve formátu dd.mm.rrrr (připouštíme oddělovač .-/) 0?[1-9]|[12][09]|3[01]([./-])0?[1-9]|1[0-2]\1[12][0-9]{3} ●
SESKUPOVÁNÍ Seskupování bez zapamatování (grouping-only patentheses) : Operátor (?: ) vytváří seskupení bez zapamatování.
POZICOVÁNÍ - KOTVY Kotvy (anchors) : Kotvy ukazují na konkrétní místa v řetězci. Z testovaného řetězce nic nekonzumují. Stříška (caret) ^ reprezentuje začátek řetězce. Znak dolaru $ reprezentuje konec řetězce. V multiline režimu pracují obě kotvy s každým řádkem zvlášť. Hranice slov (word boundaries) : Kotva \< reprezentuje začátek slova a kotva \> konec slova. PERL má kotvu reprezentující hranici slova (začátek nebo konec) \b.
MODIFIKÁTORY Modifikátory (mode modifiers) : Používají se pro změnu chování regulárního stroje, resp. změnu chování jednotlivých operátorů v regulárním výrazu. Většinou se předávají jako parametr regulárního stroje, někdy je možné je přímo vepsat do regulárního výrazu. i m s x
nerozlišuje malá a velká písmena zachází s řetězcem jako s více řádky (multiline) zachází s řetězcem jako s jedním řádkem (singleline) ignoruje bílé znaky v regulárním výrazu (free spacing and comments regex mode)
Modifikátory lze zapsat do regulárního výrazu takto (?modifikátor), např. (?i) a (?-i).
KOMENTÁŘE Komentáře (comments) : Některé implementace regulárních strojů umožňují zápis komentářů způsobem (?#komentář). Nepoužívají se ale příliš často.
VÝHLEDY Výhledy (lookarounds) : Výhled pouze zkoumá zda-li daná část řetězce vyhovuje výrazu. Podobně jako kotvy nekonzumují výhledy žádný text. Řetězec odpovídající výhledu je vždy prázdný. Výhled dopředu (lookahead) (?=výraz) (?!výraz)
Výhled dozadu (lookbehind)
Pozitivní (positive)
(?<=výraz)
Negativní (negative) (?
VÝHLEDY Výhledy (lookarounds) : Příklad : Chceme nahradit slovo Jeffs slovem Jeff's
Vyhledávací vzor:
Náhrada :
Jeffs (Jeff)(s) Jeff(?=s) (?<=Jeff)(?=s) (?=s)(?<=Jeff)
Jeff's \1'\2 Jeff' ' '
ATOMICKÉ SESKUPOVÁNÍ Atomické seskupování (atomic grouping) : Pomocí atomického seskupení lze vytvořit podvýrazy, které se při testování uplatňují kompletně celé. Není na ně uplatňován backtracking, atd. Příklad : ●
●
Regulárnímu výrazu 1.*2 vyhoví řetězec 1ahoj2. Při použití atomického seskupení 1(?>.*)2 již daný řetězec nevyhoví, neboť uvnitř skupiny není povolen backtracking !!! Regulárnímu výrazu a(bc|b)c vyhoví řetězec abcc a abc. Výrazu a(?>bc|b)c vyhoví pouze abcc !!!!
SOBECKÉ KVANTIFIKÁTORY Sobecké kvantifikátory (possesive quantifiers) : Moderní implementace regulárních strojů implementují speciální odrůdu klasických hladových kvantifikátorů *+, ++, ?+, {min,max}+. Principiálně pracují velice podobně jako atomické seskupování. Jejich použití má zejména výhodu v rychlosti vyhodnocování. Příklad : ●
Regulární výraz .++ dosahuje stejného výsledku jako (?>.+).