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 49779×

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ů

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ář

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

2.3.2016 22:41 /Ondřej Čečák
Letošní ročník konference InstallFest již tento víkend!
Přidat komentář

14.2.2016 16:39 /Redakce Linuxsoft.cz
O víkendu 5. a 6. března 2016 proběhne na pražském Strahově 8. ročník tradiční konference InstallFest. Celkem za dva dny uvidíte ​30 přednášek​ a ​6 workshopů.
Přidat komentář

5.2.2016 17:38 /Petr Ježek
Utilitka z XFce "xfce4-power-manager" nejen umožňuje nastavení lhůty pro uspání či hybernaci, ale i zapínání a vypínání prezentačního módu pro nerušené sledování videí. Stačí ji nastavit v každém vybavenějším panelu a v jakémkoli nontiled WM/DE.
Přidat komentář

10.1.2016 11:32 /Pavel `Goldenfish' Kysilka
LinuxMarket změnil provozovatele. Nově jej provozuje Marek Pszczolka. Více info a detaily #1 a #2.
Přidat komentář

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

> Poslední diskuze

10.6.2016 21:10 / pavel riha
FreeBSD 10.3 a virtualizace

8.6.2016 21:56 / Milan Gallas
Nevalidní prefix m

7.5.2016 14:58 / Teodor Komárek
Soubory

20.4.2016 0:07 / Jakub Cleing
Sázkový panel PHP FUSION

9.4.2016 9:43 / jiwopene@gmail.com
Re: problém s dpkg a nemožností instalovat

Více ...

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