Hlavní navigace

Regulární výrazy (7)

Pavel Satrapa

Na poslední díl našeho seriálu jsem si pošetřil speciality jazyka Perl. Pokud se vám při zahlédnutí jména Perl povážlivě zvedá hladina adrenalinu, podívejte se alespoň na konec článku. Najdete tam odkazy na literaturu a srovnávací tabulku speciálních znaků, kteréžto materiály by se vám mohly hodit.

Perl je do značné míry srdeční záležitost. Znám řadu jeho vášnivých zastánců a zrovna tak jeho zuřivé odpůrce. Ten jazyk je pohledem teoretika mimořádně odporný, ale zároveň neuvěřitelně mocný a praktický. Docela výstižně (a velmi vtipně) to myslím vyjádřil Jeffrey E. F. Friedl ve své knize o regulárních výrazech:

Síla Perlu může být ničivou zbraní v rukách zkušeného uživatele, zdá se však, že v Perlu sbíráte zkušenosti tak, že se opakovaně střílíte do nohy.

Dnes se ale nehodlám věnovat jazyku jako takovému. Raději se soustředím na jeho speciality v oboru regulárních výrazů. A v tomto směru je v současnosti jasná jednička, ať se to jeho odpůrcům líbí nebo ne.

Uvolněná syntax

Regulární výrazy jsou velmi kondenzované, což je bohužel činí obtížně srozumitelnými. Obecně si troufám prohlásit, že regulární výraz je často snadnější vytvořit než jej sám po sobě pochopit.

Do jazyka Perl (přesněji řečeno do verze 5, ale ta už je na světě pět let, takže ji lze považovat za standard jazyka) proto přibyla možnost rozvolnění zápisu regulárních výrazů. Nepřidává žádné nové konstrukce, jen je umožňuje srozumitelně zapsat.

Uvolněnou syntax zapíná volba x v operátoru pro hledání či nahrazování (operátory m a s). Regulární výraz se pak zapisuje do složených závorek podobně jako blok programu, ignorují se v něm mezery a konce řádků (pokud jim nepředchází zpětné lomítko) a komentáře zahájené znakem #.

Příklad:

V části o zapamatování jste se mohli setkat s nechutnou substitucí

s/([^:]*):([^­:]*:){3}([^:]*)­.*/<A HREF=„/~\1“>\3<\/A­>/

která z řádků v /etc/passwd vyráběla seznam domácích stránek uživatelů. S využitím uvolněné syntaxe bychom ji mohli přepsat následovně:

s{

   ([^:]*): ( #přihlašovací jméno (1))

   ([^:]*:){3} ( #přeskočíme heslo, UID a GID)

   ([^:]*) ( #vlastní jméno (3))

   .* ( #přeskočíme zbytek)

}{<A HREF=„/~­\1“>\3</A>}x

Nepřipadá vám to o dost srozumitelnější? Upozorňuji, že uvolněná syntax se týká pouze regulárního výrazu, nikoli nahrazujícího řetězce. V něm se projeví pouze tím, že je uzavřen do složených závorek.

Drobnosti, které potěší

Perl nabízí řadu konstrukcí, které sice nepřinášejí nějakou zásadní inovaci stran schopností regulárních výrazů, ale v běžném životě silně potěší. Asi nejčastěji používané jsou kategorie znaků. Z těch nejběžnějších lze jmenovat:

Zápis Význam Odpovídá
\d číslice [0–9]
\D nečíslice [^\d]
\w alfanumerický znak [a-zA-Z0-9]
\W nealfanumerický znak [^\w]
\s prázdný znak [\ \t\n\r]
\S neprázdný znak [^\s]

Tyto speciální znaky celkem výrazně přispívají ke srozumitelnosti regulárních výrazů. Navíc pokud svůj program zahájíte příkazem use locale, budou mezi alfanumerické znaky zařazeny i akcentované znaky národní abecedy.

Příklad:

Výměnu prvních dvou slov na řádku pak zajistí celkem mírumilovný příkaz

s/(\w+)(\W+)(­\w+)/\3\2\1/

Kromě Perlu už převzaly podobné znakové kategorie i současné verze dalších nástrojů (konzultujte s dokumentací). Kromě nich je leckde podporován i zápis kategorií podle POSIXu, kde se například číslice zapisuje jako [:digit:], alfanumerický znak jako [:alnum:] a prázdné místo [:space:]. Tyto kategorie se však zapisují mezi [], takže například řádek začínající číslicí se vyjádří pomocí ^[[:digit:]], což už má k eleganci poměrně daleko (totéž v Perlu: ^\d). Perl POSIXové kategorie nepodporuje.

Syté (též líné) opakování pomůže řešit problémy s nadměrnou žravostí opakovacích konstrukcí. Zapisuje se jednoduše: za opakovací znak (*, +, ? či {min,max}) připojíte otazník. Přípustný počet opakování se tím nijak nezmění, ale na rozdíl od klasické varianty se snaží, aby opakování bylo co nejméně. Takže třeba oblíbený řetězec v uvozovkách lze hledat pomocí „.*?“. Je to přehlednější, ale pomalejší než obvyklé řešení „[^“]*".

Třetí užitečnou drobností jsou závorky bez zapamatování. Slouží výlučně k vymezení části regulárního výrazu (např. pro opakování nebo omezení působnosti „nebo“). Vyhovující řetězec se neukládá, takže vám ubyde špetka starostí při počítání indexů těch zapamatovaných. Tyto speciální závorky se zapisují ve tvaru (?:).

Příklad:

Ještě jednou přepracuji příklad pro transformaci řádku z /etc/passwd na položku v seznamu domácích stránek. S využitím popsaných konstrukcí by mohl vypadat takto:

s{

   (.*?): ( #přihlašovací jméno (1))

   (?:.*?:){3}( #p­řeskočíme heslo, UID a GID)

   (.*?): ( #vlastní jméno (2))

   .* ( #přeskočíme zbytek)

}{<A
HREF=„/~\1“>\­2</A>}x

Tentokrát se v části přeskakující heslo, UID a GID vyhnu zapamatování, takže pod čísly 1 a 2 mám uloženy skutečně jen ty informace, které mne zajímají. Dvojtečka z konstrukce (?: se v tomto případě bohužel nepěkně plete s oddělovačem položek, ale s tím se nedá nic dělat. Líné opakování mi umožnilo poněkud zjednodušit výrazy pro jednotlivé části řádku.

Vyhlížení

Dost silný nástroj pro některé speciální případy nabízí tak zvané vyhlížení (anglicky lookahead). Existuje ve dvou odrůdách: pozitivní vyhlížení se zapisuje v podobě (?=výraz) a je splněno, pokud následující část řetězce vyhovuje výrazu. Negativní vyhlížení (?!výraz) naopak uspěje, pokud výrazu nevyhovuje. Důležité je, že vyhlížení se jen podívá, zda se vzor dá či nedá najít, ale neposouvá zkoumanou pozici dál (jemu odpovídající řetězec je vždy prázdný).

Příklad:

Vzoru \d+(?= Kč) vyhoví neprázdná posloupnost číslic, ale jen pokud za ní následuje řetězec „ Kč“. Ten však sám o sobě není zahrnut do vyhovujícího řetězce. Takže pokud příkaz

s/(\d+)(?= Kč­)/???/g

vypustíte na řetězec

Párátka 20 CX Turbo za 25 Kč kus

obdržíte výsledek

Párátka 20 CX Turbo za ??? Kč kus

Za příklad negativního vyhlížení může posloužit (?!000)\d\d\d, kterému vyhoví libovolná trojice číslic s výjimkou 000.

Faktem je, že vyhlížení není principiálně nezbytné. Zpravidla je lze nahradit jinými konstrukcemi jazyka. Například zachování „ Kč“ za skupinou číslic by se dalo zařídit pomocí zapamatování. Test na trojici číslic, ne však 000 by se dal rozložit do dvou nezávislých testů a podobně. V některých případech však vyhlížení dává zajímavé možnosti.

Příklad:

Hezkou vychytávkou využívající vyhlížení je oddělování řádů ve velkých číslech. Mezi trojice číslic se mají vložit mezery, takže z „12345678“ vznikne „12 345 678“. Vtip je v tom, že se trojice počítají odzadu, na což regulární výrazy nejsou příliš zařízené. Vyhlížení umožňuje následující řešení:

s{

   (\d{1,3}) ( #za první s­kupinu patří me­zera)

   (?= ( #ale jen když následuje)

      (?:\d\d\d)+ (
 #alespoň jedna trojice číslic)

      (?!\d) ( #a tím číslo končí)

   ) ( )

}{\1 }gx

Díky vyhlížení se můžete přesvědčit, že počet číslic, které následují za aktuální pozicí ve zpracovávaném řetězci, je násobkem tří. Vyhlížení zároveň zajistí, že se tato pozice nezmění a že se při příštím opakování (díky volbě g se provádí pro všechny výskyty) se bude pokračovat za naposledy vloženou mezerou.

Literatura

Pokud je mi známo, vyšla zatím jediná kniha věnovaná výlučně regulárním výrazům. Napsal ji Jeffrey E. F. Friedl a jmenuje se Mastering Regular Expressions (vydalo nakladatelství O'Reilly & As­sociates v roce 1997, ISBN 1–56592–257–3). Není to pochopitelně vyslovená oddechovka, ale v rámci možností vysvětluje vlastnosti regulárních výrazů, vhodné a nevhodné techniky pro jejich vytváření. Vzhledem k rozsahu přes 300 stran si může dovolit jít dost do hloubky.

Cenné služby odvede kniha Unix Power Tools, jejímiž autory jsou Jerry Peek, Tim O'Reilly a Mike Loukides. Vyšla také u O'Reilly & As­sociates v roce 1997 (2. vydání, ISBN 1–56592–260–3). Obsahuje velmi slušnou kapitolu o regulárních výrazech a kromě ní řadu tipů a triků na využívání programů, které s nimi pracují. Osobně ji považuji za jednu z nejpřínosnějších knížek, které jsem kdy měl v ruce.

Přehledová tabulka

Jako závěrečnou přílohu vám nabízím stručný přehled regulárních výrazů v nejběžnějších nástrojích. Konkrétně se jedná o GNU grep a egrep verze 2.3, GNU awk verze 3.0.4, vim verze 5.5 a Perl verze 5.005_03. Tabulka je k dispozici v těchto formátech: PostScript, PDF, HTML.

Našli jste v článku chybu?

5. 11. 2015 9:15

Martin (neregistrovaný)

V RegExu jsem leta jen letal, a chybeli mi zaklady, takove ty drobnosti, jako ze tecka uvnitr [] neni specialni atd. Dokazal jsem RegEx formulovat, ale uz ne zapsat.

Serial je naspany uzasnou formou, a moc za nej dekuji, vse je jasne a pochopitelne vysvetleno.

Diky!

19. 5. 2010 19:55

bany (neregistrovaný)

Zajimalo by me jak to pomoci prikazove radky ( perl -pe ‚…‘) lze udelat?

Lupa.cz: Insolvenční řízení kvůli cookies? Vítejte v ČR

Insolvenční řízení kvůli cookies? Vítejte v ČR

Vitalia.cz: Paštiky plné masa ho zatím neuživí

Paštiky plné masa ho zatím neuživí

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

DigiZone.cz: Test Philips 24PFS5231 s Bluetooth repro

Test Philips 24PFS5231 s Bluetooth repro

Lupa.cz: Kdo pochopí vtip, může jít do ČT vyvíjet weby

Kdo pochopí vtip, může jít do ČT vyvíjet weby

DigiZone.cz: Recenze Westworld: zavraždit a...

Recenze Westworld: zavraždit a...

Vitalia.cz: Proč vás každý zubař posílá na dentální hygienu

Proč vás každý zubař posílá na dentální hygienu

Podnikatel.cz: K EET. Štamgast už peníze na stole nenechá

K EET. Štamgast už peníze na stole nenechá

Podnikatel.cz: Zavře krám u #EET Malá pokladna a Teeta?

Zavře krám u #EET Malá pokladna a Teeta?

Podnikatel.cz: Snížení DPH na 15 % se netýká všech

Snížení DPH na 15 % se netýká všech

Podnikatel.cz: EET: Totálně nezvládli metodologii projektu

EET: Totálně nezvládli metodologii projektu

Vitalia.cz: I církev dnes vyrábí potraviny

I církev dnes vyrábí potraviny

Vitalia.cz: Jsou čajové sáčky toxické?

Jsou čajové sáčky toxické?

Měšec.cz: mBank cenzuruje, zrušila mFórum

mBank cenzuruje, zrušila mFórum

Root.cz: Certifikáty zadarmo jsou horší než za peníze?

Certifikáty zadarmo jsou horší než za peníze?

Podnikatel.cz: 1. den EET? Problémy s pokladnami

1. den EET? Problémy s pokladnami

Podnikatel.cz: Podnikatelům dorazí varování od BSA

Podnikatelům dorazí varování od BSA

120na80.cz: Co všechno ovlivňuje ženskou plodnost?

Co všechno ovlivňuje ženskou plodnost?

Měšec.cz: Zdravotní a sociální pojištění 2017: Připlatíte

Zdravotní a sociální pojištění 2017: Připlatíte

Podnikatel.cz: Udávání a účtenková loterie, hloupá komedie

Udávání a účtenková loterie, hloupá komedie