Hlavní navigace

Regulární výrazy (4)

28. 4. 2000
Doba čtení: 3 minuty

Sdílet

Po krátké odbočce se vracíme k opakování. Onu přestávku věnovanou programům podporujícím regulární výrazy jsem zařadil jednak abych předvedl nějaké praktické využití, jednak proto, že již nebude možné skrývat existenci různých dialektů. Různé programy totiž podporují lehce odlišné varianty regulárních výrazů. Ty, o kterých jsem mluvil až dosud, byly společné pro všechny. Dnes už narazíme na některé odlišnosti.

Omezený počet opakování

Základním problémem klasické opakovací hvězdičky je, že je nekontrolovatelná. Pro některé situace potřebujete přesnější vyjadřování.

Vaše touhy uspokojí konstrukce \{min,max\}. Opět se vztahuje na bezprostředně předcházející regulární výraz a říká, že se má opakovat alespoň min-krát, nanejvýš však max-krát. Jako každé opakování i tohle je hladové, takže se snaží uplatnit vždy co největší z povoleného počtu opakování.

Příklad:

Regulárnímu výrazu i\{1,3\} vyhoví řetězce „i“, „ii“ nebo „iii“.

Tvar tohoto opakovátka je velmi variabilní. Pokud chybí horní mez (\{min,\}), znamená to, že maximální počet opakování je neomezený. Jestliže v konstrukci použijete jen samotné číslo (\{počet\}), musí se regulární výraz opakovat přesně daný počet-krát.

Příklad:

Regulární výraz pro rodné číslo by vypadal takto:

[0-9]\{6\}/[0-9]\{3,4\}

Šest číslic, lomítko a ještě tři nebo čtyři číslice.

A již tu máme první odlišnost. V některých verzích regulárních výrazů (například v Perlu) se při omezování počtu opakování před složenými závorkami nepíší zpětná lomítka. Zapíšete-li zde \{, znamená to, že zkoumaný text má obsahovat znak „{“. Perl má pro tuto specialitu dobrou omluvu: zavedl pravidlo, že kombinace zpětného lomítka a znaku odlišného od písmena či číslice nikdy nemá speciální význam a vždy představuje dotyčný znak.

Nejpopulárnější opakovačky

Dva velmi populární případy opakování si vysloužily svůj vlastní speciální znak. Prvním je „alespoň jeden výskyt“ - tedy cosi velmi podobného klasické opakovací hvězdičce, až na to, že opakovaný regulární výraz nelze vynechat. Stejného efektu dosáhnete konstrukcí \{1,\}, ale to je příliš složité psaní. Proto se alespoň jeden výskyt předchozího regulárního výrazu zapisuje znakem plus (+).

Druhou populární situací je nepovinný (čili nanejvýš jeden) výskyt. Opět jej lze zapsat pomocí \{0,1\}, ale kratší je otazník (?).

Dialekty regulárních výrazů se u této dvojice znaků opět silně rozcházejí. Programy používající klasické regulární výrazy (grep, sed, vi) jim předřazují zpětné lomítko (\+ a \?). Generace, která implementuje rozšířené regulární výrazy, (egrep, awk, Perl) je píše bez něj (+ a ?).

Příklad:

Alespoň jedna číslice se tedy v grep, sed a vi vyjádří pomocí [0–9]\+, zatímco egrep, awk či Perl nabízí kratší [0–9]+. Zápis můžeme lehce rozšířit na regulární výraz pro celé číslo: nepovinné znaménko následované alespoň jednou číslici. V klasických regulárních výrazech to bude [-+]\?[0–9]\+, zatímco v rozšířených [-+]?[0–9]+.

Pozice

Výrok „dejte mi pevný bod a pohnu zeměkoulí“ jistě znáte. Nahlíženo jeho optikou byly všechny naše dosavadní regulární výrazy poněkud neukotvené. Řetězec, který jim vyhovuje, se mohl vyskytovat kdekoli ve zkoumaném textu. Občas však člověk musí být přísnější.

Proto regulární výrazy nabízejí několik speciálních pozičních znaků. Těmi nejznámějšími jsou stříška (^), která ztělesňuje začátek řádku (resp. zkoumaného řetězce znaků), a dolar ($) označující jeho konec.

Cloud 24 - tip 1

Příklad:

grep ‚^#‘ vám tedy najde řádky začínající znakem ‚#‘, grep ‚[0–9]$‘ řádky končící číslicí a konečně grep ‚^-\+$‘ řádky složené pouze z pomlček (nikoli však prázdné).

Dalším významným místem je hranice slova. Ve většině regulárních dialektů máte k dispozici konstrukci \<, která označuje začátek slova, a \>, které vyhoví pouze jeho konec.

Perl nerozlišuje začátek slova od konce, má pouze speciální znak \b pro „hranici slova“ (tedy začátek nebo konec). Ovšem dlužno přiznat, že z okolního kontextu bývá zřejmé, zda \b může vyhovět začátek nebo konec slova. Jako cenu útěchy získáváte v Perlu ještě \B, kterému vyhoví libovolné místo ve zkoumaném řetězci kromě hranice slova. Jedná se tedy o negaci \b.

Příklad:

Zajímají-li vás všechny řádky, na nichž se písmeno ‚a‘ vyskytuje v roli jednopísmenné spojky, nasaďte

grep '\<a\>'

Totéž v Perlu (až na to, že se nevypisují jména souborů) by zajistil příkaz

perl -ne 'print if /\ba\b/'

Pokud se názvů souborů nehodláte vzdát, použijte

perl -ne 'print "$ARGV:$_" if /\ba\b/'

Shrnutí

výraz znamená
* libovolný počet opakování předchůdce
+ nebo \+ alespoň jeden výskyt předchůdce
? nebo \? nanejvýš jeden výskyt předchůdce
{min,max} nebo \{min,max\} alespoň min a nanejvýš max výskytů předchůdce
^ začátek řádku
$ konec řádku
\< nebo \b začátek slova
\> nebo \b konec slova

Byl pro vás článek přínosný?

Autor článku

Pavel Satrapa působí na Ústavu nových technologií a aplikované informatiky na Technické univerzitě v Liberci, píše knihy a motá se kolem tuzemské akademické sítě CESNET.