LINUXSOFT.cz Přeskoč levou lištu
Uživatel: Heslo:  
   CZUKPL

> Perl (16) - Regulární výrazy - začínáme

Dneškem začíná v rámci seriálu Perl miniseriál o nesmírně mocném nástroji - regulárních výrazech.

19.10.2005 07:00 | Jiří Václavík | Články autora | přečteno 50262×

Regulární výrazy (anglicky regular expressions, někdy zkráceně označované jako regexp, regex nebo RE) jsou reprezentací regulárních jazyků v teorii konečných automatů.

Jejich aplikace (ve smyslu zda řetězce odpovídají vzoru) se poprvé objevila v unixových nástrojích pro editaci a vyhledávání v řetězcích - tedy sed, vi, grep, awk a další (více o historii například na Wikipedii). Nejsou mezi sebou úplně kompatibilní, protože většinou bylo k původním regulárním výrazům něco přidáno (potom tedy reprezentují nadmnožinu regulárních jazyků). V praxi se to projevuje tak, že to, co funguje awku, nemusí fungovat v grepu nebo může mít jinou syntaxi apod.

Mezi nástroje, které umí regulární výrazy se samozřejmě řadí i Perl. Jen těžko byste hledali jiný jazyk, který by podporoval regulární výrazy odpovídající tak silné množině jazyků. Navíc spojením kvalitního skriptovacího jazyka s regulárními výrazy získáváme do svého arzenálu nesmírně silný nástroj. Toto je jeden z hlavních důvodů, proč se Perl těší oblibě, kterou má. Proto ani zde nebudeme regulárními výrazy šetřit a pokusíme se je přiblížit opravdu podrobně.

Co je to regulární výraz?

Regulární výraz si můžeme představit jako speciální řetězec, který je šablonou vystihující určitý jazyk (tj. množinu textových řetězců). Každý textový řetězec takové šabloně buď vyhovuje nebo ne. S touto množinou vyhovujících řetězců můžeme manipulovat - hledat její prvky v textu nebo je nahrazovat jiným řetězcem.

Vzpomeňme si, že jsme na regulární výrazy již natrefili při popisu funkcí grep a split. To jsme ale jen uvedli příklady a dále je nerozebírali.

Formální definice regulárních výrazů

Nechť X = {x1, ..., xn} je nějaká konečná neprázdná abeceda a l označuje prázdné slovo. Pak množinou všech regulárních výrazů RE(X) nad abecedou X je nejmenší množina slov v abecedě {x1, ..., xn, {}, l, *, +, ., (, )}, pro kterou platí:

  • RE(X) obsahuje každý prvek abecedy X, dále pak l a {}
  • Jsou-li r, s v RE(X), pak je tam i r+s a r.s
  • Je-li r v RE(X), pak je tam i r*

Regulárním výrazem tedy je například (((a*((b+c).d)*)+e)*f). Některé závorky a tečky lze po dohodě vynechat a můžeme psát ((a*(b+cd)*)+e)*f.

Hodnotou regulárního výrazu r je jazyk L = [r], pro který platí:

  • [{}] = {}
  • [l] = {l}
  • [x] = {x} pro všechna písmena z abecedy X
  • [(r+s)] = [r] sjednoceno s [s]
  • [(r.s)] = [r] . [s]
  • [r*] = [r]*

Regulární výrazy odpovídají regulárním jazykům. Regulární výrazy v Perlu jsou nadmnožinou formální definice. Třeba proto, že obsahují i jazyk L = {0n1n}, který regulární není. Ačkoliv to není formálně v pořádku, budeme je nazývat regulárními výrazy i nadále.

Regulární výrazy versus žolíkové znaky

Regulární výrazy jsou někdy zaměňovány se žolíkovými znaky. Obecně, žolíkový znak může vyhovovat jednomu nebo více znakům. Oproti tomu regulární výraz je řetězec s jasně určenými podmínkami a žádný samotný znak zde nezastupuje více znaků. Například * v žolíkových znacích znamená libovolný řetězec, ale v regulárních výrazech libovolný počet opakování. Žolíkové znaky se používají téměř výhradně k hledání v názvech souborů.

Regulární výrazy v Perlu

Základní syntaxe

Regulární výraz (od teď již jen v perlové terminologii) je výraz, který má dvě možné vyhodnocení - buď true nebo false. To znamená, že následující zápis vrací 1, pokud se v řetězci vyskytuje podřetězec "vzor", v opačném případě prázdný řetězec.

"řetězec" =~ m/vzor/

Regulárnímu výrazu m/vzor/ vyhoví takové řetězce jako "vzory", "re vzor" nebo "vzor". Operátor =~ slouží k porovnávání vzorů. S přiřazováním má společný opravdu jen ten znak rovnítka, jinak jde o odlišné operace.

Následující díly seriálu se tedy budou věnovat prakticky pouze tomu, co napsat místo vzoru, abychom vytvořili požadovanou šablonu. Dodejme, že v Perlu 6 dojde ke kompletnímu přepracování regulárních výrazů a už nepůjde jen o úpravu jednoho řetězce. Budou mít podstatně intuitivnější strukturu, více integrované do jazyka a navíc ještě o něco silnější.

Další možná uvození

Uvozující m není povinné, navíc můžeme stejně jako u nám už známých q a qq lomítka nahradit jiným znakem. Negovaný operátor =~ se zapisuje jako !~.

print "řetězec" =~ m"vzor";
print "řetězec" =~ m!vzor!;
print "řetězec" =~ /vzor/; #nejběžnější užití
print "řetězec" !~ /vzor/;

Existuje několik speciálních ohraničení pro regulární výrazy. Použijí-li se apostrofy, neprobíhá vkládání obsahu proměnných. Nelze tedy psát:

$vzor = "[abc]{2}";
"aa" =~ m'$vzor'; #$vzor není nahrazen obsahem proměnné, ale je brán jako řetězec '$vzor'

Další možností je ohraničení otazníky (potom uvedení m není povinné). V takovém případě dojde k použití vzoru pouze jednou (i v testu cyklu s modifikátorem g). Teprve až je zavolána funkce reset, může se porovnání opakovat. Tuto konstrukci uvádíme pouze pro zajímavost a nelze ji doporučovat. My se budeme striktně držet používání lomítek.

Užití v testech podmínek

Porovnávání řetězců se užívá jako test při rozhodování.

$veta = "Existuje 10 druhů lidí - ti, kteří znají binární kód, a ti, kteří ne.";

if ($veta =~ m/10 druhů/){
    print "'10 druhů' je ve větě!\n"
}

if ($veta =~ m/777/){
    print "'777' je ve větě!\n"
}

"10 druhů" se v řetězci vyskytuje, proto byl v tomto případě výraz vyhodnocen jako true. Nezáleží na tom na jaké pozici nebo co je okolo.

Použití výchozí proměnné

Je také možné uvést jako test podmínky jen čistě regulární výraz v uvozovacích znacích. Implicitně je porovnáván s výchozí proměnnou. Příklad má stejný účinek jako předchozí, ale využívá této vlastnosti:

$_ = "Existuje 10 druhů lidí - ti, kteří znají binární kód, a ti, kteří ne.";

if (/existuje/){
    print "'existuje' je ve větě!\n"
}

if (/Existuje/){
    print "'Existuje' je ve větě!\n"
}

Poslední ukázka tiskne řetězec "'Existuje' je ve větě!". Na velikosti písmen tedy implicitně záleží. Způsob, kterým lze toto chování změnit, si představíme v jednom z příštích dílů.

V případě zkráceného zápisu pomocí výchozí proměnné je též možné negovat. Stačí přidat vykřičník před úvodní /.

if (!/2 druhy/){
    print "'2 druhy' není ve větě!\n"
}

Metaznaky

Mezi lomítka lze napsat všechny znaky znaky kromě takzvaných metaznaků. Mají totiž nějakou jinou funkci. Patří mezi ně *, +, ., ?, ^, $, (, ), {, }, [, ], |, /. Lze je nahradit předřazením zpětného lomítka. Pokud si nejste jisti, zda má znak speciální význam a není alfanumerický (tedy pokud je z množiny \W), můžeme mu předřadit zpětné lomítko vždy. Sekvence zpětného lomítka a nealfanumerického znaku se chová vždy jako znak bez speciálního významu.

Proměnné v regulárních výrazech

Než se začne regulární výraz vyhodnocovat, jsou nahrazeny proměnné ve vzoru svým obsahem (což ale samozřejmě neplatí u ohraničení pomocí apostrofů).

$cisla = "2005";
print "0002005000" =~ /$cisla/;

Druhý řádek předchozího kódu bude fungovat takto:

print "0002005000" =~ /2005/;

Návratová hodnota výrazu řetězec =~ vzor

Tuto část lze zatím klidně přeskočit, protože je zde řada věcí, které jsme zatím neprobírali. Je to ale téma, které by v prvním dílu o regulárních výrazech chybět nemělo.

skalární kontext

Ve skalárním kontextu vrací v případě úspěchu 1, v případě neúspěchu nepravdivou hodnotu.

seznamový kontext

O něco složitější je to v seznamovém kontextu. Při neúspěchu bez modifikátoru g vrací prázdný seznam. V případě úspěchu vrací seznam zapamatovaných hodnot, pokud jsou, jinak vrací seznam (1). S modifikátorem g vrací výraz pole vyhovujících podřetězců.

$retezec = "12345";
@return1 = $retezec =~ /\d\d\d/;
@return2 = $retezec =~ /(\d)(\d)(\d)/;
@return3 = $retezec =~ /(\d)/g;

Pole @return1 obsahuje prvek (1). Žádná hodnota nebyla zapamatovaná. Oproti tomu v poli @return2 už takové hodnoty byly: jeho prvky (1, 2, 3) jsou právě zapamatovanými hodnotami. Poslední pole obsahuje (1, 2, 3, 4, 5), protože se vzor aplikoval celkem 5×.

Verze pro tisk

pridej.cz

 

DISKUZE

Nejsou žádné diskuzní příspěvky u dané položky.



Příspívat do diskuze mohou pouze registrovaní uživatelé.
> Vyhledávání software
> Vyhledávání článků

4.9.2016 20:13 /Pavel `Goldenfish' Kysilka
PR: Dne 22.9.2016 proběhne v Praze konference Cloud computing v praxi. Tématy bude např. nejnovější trendy v oblasti cloudu a cloudových řešení, provozování ERP v cloudu, o hostování různých typů softwaru, ale třeba i o zálohování dat nabízeném podnikům formou služby.
Přidat komentář

1.9.2016 11:27 /Honza Javorek
Česká konference o Pythonu, PyCon CZ, stále hledá přednášející skrz dobrovolné přihlášky. Máte-li zajímavé téma, neváhejte a zkuste jej přihlásit, uzávěrka je již 12. září. Konference letos přijímá i přednášky v češtině a nabízí pomoc s přípravou začínajícím speakerům. Řečníci mají navíc vstup zadarmo! Více na webu.
Přidat komentář

27.8.2016 8:55 /Delujek
Dnes po 4 letech komunitního vývoje vyšla diaspora 0.6.0.0
diaspora* je open-source, distribuovaná sociální síť s důrazem na soukromý
Více v oficiálním blog-postu
Přidat komentář

24.8.2016 6:44 /Ondřej Čečák
Poslední týden CFP LinuxDays 2016; pokud byste rádi přednášeli na LinuxDays 2016 8. a 9. října v Praze, můžete svůj příspěvek přihlásit, následovat bude veřejné hlasování.
Přidat komentář

9.8.2016 22:56 /Petr Ježek
Zařazení souborového systému reiser4 do jádra 4.7 znamená konečně konec patchování jádra jen kvůli možnosti použít reiser4.
Přidat komentář

12.7.2016 13:14 /František Kučera
Spolek OpenAlt zve na 130. distribuovaný sraz příznivců svobodného softwaru a otevřených technologií (hardware, 3D tisk, SDR, DIY, makers…), který se bude konat ve čtvrtek 21. července od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5).
Přidat komentář

11.7.2016 16:53 /Redakce Linuxsoft.cz
Konference LinuxDays hledá přednášející. Přihlášky poběží do konce prázdnin, v září bude hlasování a program. Více na https://www.linuxdays.cz/2016/cfp/.
Přidat komentář

8.5.2016 17:19 /Redakce Linuxsoft.cz
PR: Dne 26.5.2016 proběhne v Praze konference Cloud computing v praxi. Tématy bude např. nejnovější trendy v oblasti cloudu a cloudových řešení, cloudové služby, infrastruktura cloudu, efektivní využití cloudu, možné nástrahy cloudů a jak se jim vyhnout
Přidat komentář

   Více ...   Přidat zprávičku

> Poslední diskuze

19.9.2016 21:04 / Marek Schoř
Poděkování

1.9.2016 13:07 / Walker
hardwood floor refinishing

12.8.2016 11:51 / Josef Zapletal
Jak udělat HTML/Javascript swiping gallery do mobilu?

8.8.2016 14:58 / Adams
fairies for hire

28.7.2016 15:51 / pepan
Re: NetBeans vs Eclipse

Více ...

ISSN 1801-3805 | Provozovatel: Pavel Kysilka, IČ: 72868490 (2003-2016) | mail at linuxsoft dot cz | Design: www.megadesign.cz | Textová verze