LINUXSOFT.cz Přeskoč levou lištu

ARCHIV



   

> Perl (18) - Regulární výrazy - množiny znaků

Ve 3. pokračování o regulárních výrazech jsou představeny třídy znaků.

3.11.2005 13:00 | Jiří Václavík | Články autora | přečteno 48214×

Množina znaků je skupina obyčejných znaků. Pokud ji uvedeme ve vzoru, potom se taková množina chová jako 1 ze znaků, které obsahuje. Máme několik možností, jak množinu definovat.

libovolný znak

Začneme tím nejjednodušším. Znak tečka zastupuje 1 libovolný znak mimo konce řádků.

Poznámka - Pokud chcete zahrnout do množiny znaků, které tečka zastupuje i znak konce řádku, použijte přepínač /s.

Příklad vypisuje slova s názvem o délce 4:

  @slova = qw(C++ Perl Python Ruby Java);
  foreach $slovo (@slova){
      print $slovo, "\n" if ($slovo =~ /^....$/); #vypíší se slova, které zabírají 4 znaky
  }

Poznámka - Nutno ale poznamenat, že místo cyklu foreach bychom mohli jednoduše použít funkci grep:

  $, = "\n";
  print grep /^....$/, @slova;

Výčet znaků

Je možné specifikovat užší množinu znaků než libovolný znak. K tomu slouží hranaté závorky. Skupina znaků, které jsou v hranatých závorkách, tvoří tuto užší množinu. Znaky nejsou nijak speciálně odděleny, protože to není potřeba.

  print "MATCHED" if "SUSE Linux 9.2" =~ /S[Uu]SE Linux 9\.[123]/;
  print "MATCHED" if "SuSE Linux 9.3" =~ /S[Uu]SE Linux 9\.[123]/;
  print "MATCHED" if "SUSE Linux 9.4" =~ /S[Uu]SE Linux 9\.[123]/;

1. a 2. příklad vrací 1, poslední příklad prázdný řetězec. Číslo 4 totiž není v dané množině povolených znaků.

Pomocí alternace můžeme vytvořit vzor, kterému vyhoví i "SUSE Linux 10.0".

  print "MATCHED" if "SUSE Linux 10.0" =~ /S[Uu]SE Linux (9\.[123]|10\.0)/;

Poznámka - Zde návratová hodnota obsahuje zapamatované hodnoty. Pamatování jsme zatím neřešili.

Zkusme si spočítat, kolika různým řetězcům náš poslední vzor vyhoví. Aby to nebylo nekonečno, vzor nejdříve ukotvíme:

  /^S[Uu]SE Linux (9\.[123]|10\.0)$/

Nyní pojďme znak po znaku (resp. množinu po množině), u každého zjistíme počet možností, a tyto počty mezi sebou vynásobíme. 1. znak, S, je samostatný znak - tedy množina jediného znaku. [Uu] je množina 2 znaků a jsou tedy 2 možnosti. Dále máme až k závorce vždy 1 možnost. Potom následuje 1 z řetězců 9.1, 9.2, 9.3 nebo 10.0. Tedy 4 možnosti. Velikosti množin mezi sebou vynásobíme, a tím získáváme 1*2*1*1*1*1*1*1*1*1*1*4 = 8. Naší šabloně tak vyhoví 8 řetězců.

Pro výčet znaků existuje několik usnadnění. Představte si, že chcete definovat množinu, které vyhovuje libovolné anglické písmeno. Řešení může vypadat například takto: [abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]. Jistě uznáte, že to není to pravé. Je možné si ale nadefinovat proměnné, kde budou skupinu znaků obsahovat a následně je použít asi takto ve vzoru:

  $pismeno = "[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]";
  print "r" =~ /$pismeno/;

Znaky v množinách se speciálním významem

Stále to je příliš těžkopádné. Regulární výrazy nabízejí mnohem lepší řešení. Existuje totiž speciální operátor rozsahu. Ten se zapisuje v syntaxi regulárních výrazů pomlčkou. Předchozí problém s množinou všech písmen se tímto způsobem řeší mnohem pohodlněji. Do vzoru stačí uvést [a-zA-Z]. To samé lze dělat s čísly. [2-5] je totéž, co [2345]. Množninu znaků, které vyhoví číslice šetnáckového zápisu čísla, tak zapíšeme jako [0-9a-fA-F].

Zkuste si tipnout, co všechno vyhoví zápisu ^[x|y]$. Ač to možná intuitivně vypadá jako znak x nebo znak y, má tento zápis úplně jiný význam. Znak | nemá na tomto místě žádnou speciální funkci, proto celému regulárnímu výrazu vyhovuje znak x, y nebo |.

Jedním z těchto speciálních znaků je ^ (negace - pozor!, se začátkem řetězce má společné jen to, že používá stejný symbol). Užijete ji, pokud například chcete definovat množinu, které mají vyhovovat všechny znaky kromě velkých písmen. Píše se bezprostředně za úvodní hranatou závorku (pokud je jinde, svoji funkci ztrácí). Má ten efekt, že to, co je obvykle množinou znaků, je jejím doplňkem. Náš problém s vynecháním velkých písmen vyřešíme takto: [^A-Z] (oproti tomu v zápisu [a-c^d-f] stříška speciální význam nemá, protože již není na 1. pozici).

Stejně jako stříška ztrácí uvnitř hranatých závorek svoji funkci na jiném než 1. místě, ztrácí ji i uzavírací závorka na 1. místě. Pokud je tam uvedete, bere se jen jako znak z množiny. Je-li umístěna jinam, musíte jí předřadit zpětné lomítko. To samé platí pro pomlčku - speciální funkci má pouze, pokud dostane z obou stran nějaké smysluplné hodnoty. V opačném případě totiž buď hlásí Invalid range (je-li na jedné straně písmeno, na druhé číslo, nebo když jsou strany prohozeny), a nebo bere pomlčku jako znak bez speciálního významu (pokud je uvedena na začátku nebo na konci řetězce v hranatých závorkách).

Nejen na alfanumerické znaky se může rozsah vztahovat. Lze zadat osmičkové rozpětí znaků z ASCII tabulky. Například znaky ( (osmičkový kód 050), ) (051), * (052), + (053). Následující 2 zápisy jsou ekvivalentní:

  /^[()*+]$/
  /^[\050-\053]$/

čeština

Operátor rozsahu se na české znaky nevztahuje. Jinak je to ale s předdefinovanými množinami znaků. Použijete-li příkaz use locale; a máte-li správně nastavené proměnné prostředí, vztahují se množiny i na národní znaky.

  use locale;
  print "MATCHED" if "č" =~ /\w/;

Je vytisknuto MATCHED, protože znak s háčkem množině vyhovuje. Zkuste nyní odstranit use locale;. Potom toto tvrzení platit nebude.

Předdefinované množiny

Další elegantní řešení nabízejí předdefinované množiny znaků. Existují speciální escape sekvence, které je zastupují. Přitom se nemusejí uzavírat hranatými závorkami. Pro srovnání do tabulky zahrnuji i tečku.

Escape znakEkvivalentní zápisVýznam
\d[0-9]Číslice
\D[^0-9] nebo [^\d]Cokoliv mimo číslici
\w[_0-9a-zA-Z]Znaky identifikátorů
\W[^_0-9a-zA-Z] nebo [^\w]Cokoliv mimo znaků identifikátorů
\s[\ \n\r\t\f]Bílý znak
\S[^ \n\r\t\f] nebo [^\s]Cokoliv mimo bílého znaku
.[^\n]Libovolný znak mimo znaku nového řádku (chování se dá pozměnit přepínačem s)

Poznámka - Ekvivalenty \w a [_0-9a-zA-Z]) resp. \W a [^_0-9a-zA-Z] v poslední tabulce nejsou skutečně 100% ekvivalenty. Vzory [_0-9a-zA-Z] a \w se mají chovat stejně, ale v případě použití locales tomu tak není. Předveďme si důkaz:

  use locale;
  print "MATCHED" if "č" =~ /\w/;           #true
  print "MATCHED" if "č" =~ /[_0-9a-zA-Z]/; #false

Nyní zapíšeme regulární výraz pro formát 12hodinového zápisu času.

  /^[01]\d[:\.][0-5]\d[:\.][0-5]\d[ ]?[pPaA][mM]$/;

Vysvětleme si, jak se tento regulární výraz vyhodnocuje:

  • ^ - začátek řetězce
  • [01] - znak 0 nebo 1
  • \d - znak z číslic 0 až 9
  • [:\.] - Znak : nebo . (tečka). Oddělovač hodin a minut
  • [0-5]\d - číslo mezi 00 a 59. Počet minut
  • poslední 2 body se opakují pro vyjádření sekund
  • [ ]? - nepovinná mezera
  • [pPaA][mM] - určuje, zda se jedná o dopoledne nebo odpoledne (povinné).
  • $ - konec řetězce

Je tu problém. Našemu výrazu vyhoví i čas 13 - 19 hodin. Musíme použít znak |. 1. operand bude hledat, zda jsou hodiny mezi 00 a 09, pokud ne, 2.operand zjistí zda nejsou ještě mezi 10 až 12.

  /^((0\d)|(1[0-2]))[:\.][0-5]\d[:\.][0-5]\d[ ]?[pPaA][mM]$/;

Regulárnímu výrazu ((0\d)|(1[0-2])) vyhovují čísla 01 až 12, zbytek je stejný jako v minulém příkladu. Celý výraz ještě o něco zjednoduší přepínač /i. Zápis [pPaA][mM] pak může vypadat o něco pohodlněji.

  /^((0\d)|(1[0-2]))[:\.][0-5]\d[:\.][0-5]\d[ ]?[pa]m$/i;

Sice ani toto není dokonalé řešení (vyhoví i takové věci jako "10.10:40pM"), ale pro představu nám posloužilo.

Unicode třídy

Toto asi nebudete nikdy potřebovat, ale koho to zajímá ať čte dál. Třída znaků se zadává pomocí zápisu \p{třída}. Pokud chceme doplněk třídy (tedy vše mimo toho, co do třídy patří), použijeme zápis \P{třída}.

V 1. tabulce jsou jen pro představu 2 Unicode třídy. Existuje jich ale mnohem více (man perlretut).

TřídaVýznam
IsSmmatematický symbol
IsScznaky měny

Znakem měny je například dolar:

  print "MATCHED" if "r" =~ /^\p{IsSc}$/ #nevyhovuje
  print "MATCHED" if "\$" =~ /^\p{IsSc}$/; #vyhovuje

Dále si Perl některé třídy sám definuje.

Mají 2 možnosti zápisu. Buď \p{třída} nebo [:třída:]. Zápis [:třída:] je možný jen uvnitř dalších [ ]. Samotné [:třída:] by totiž znamenalo množinu znaků :, t, ř, í, d, a. Je tedy nutný zápis [[:třída:]].

UNICODE \p{třída}POSIX [:třída:]Význam
IsAlphaalphaAnglická písmena
IsAlnumalnumAnglická písmena a číslice
IsASCIIasciiZnaky ASCII 0-127
IsSpaceblankMezera, tabulátor
IsCntrlcntrlŘídící znaky
IsDigitdigitČíslice
IsGraphgraphGrafické
IsLowerlowerMalá anglická písmena
IsPrintprintTisknutelné znaky a mezera
IsPunctpunctInterpunkce a pomocné znaky
IsSpacePerlspaceBílý znak
IsUpperupperVelká anglická písmena
IsWordwordAlfanumerický znak nebo podtržítko
IsXDigitxdigitŠestnáckové číslo

Použití ukazuje následující kód. Všimněte si odlišných barev hranatých závorek. Vnější definují množinu znaků, jejíž obsahem je třída xdigit.

  print "MATCHED" if "5" =~ /^[[:xdigit:]]$/; #vyhovuje - 5 je hexadecimální
  print "MATCHED" if "a" =~ /^[[:xdigit:]]$/; #vyhovuje - a je hexadecimální
  print "MATCHED" if "g" =~ /^[[:xdigit:]]$/; #nevyhovuje - g není hexadecimální

Perl umožňuje POSIX třídy negovat. Negovaná [:třída:] je [:^třída:].

Na závěr ještě něco k definici unicode tříd. Je nutné vytvořit podprogram se stejným jménem jako třída. Jeho návratovou hodnotou jsou řádky. Je-li na řádku 1 číslo, určuje ASCII znak, určený 16kově. Jsou-li na řádku 2 čísla, oddělená mezerou, jde o rozsah. Definujeme si třídu IsZavorka, které vyhoví 1 ze znaků (, ), {, }, [, ], <, > - tedy závorka kulatá, složená, hranatá nebo lomená.

  print "MATCHED" if "(" =~ /^\p{IsZavorka}$/; #vyhovuje
  
  sub IsZavorka {
      return <<END;
  28 29
  3C
  3E
  5B
  5D
  7B
  7D

  END
  }

Třídy lze definovat i pomocí již definovaných tříd. V takovém případě je do návratové hodnoty podprogramu třeba uvést řádek [+!-&]balík::Trida. Implicitní unicode třídy jsou v balíku utf8. + (sjednocení) funguje pro přidání znaků z příslušné třídy, ! (rozdíl) pro odebrání znaků, - (doplněk) pro všechny znaky mimo znaky z této třídy a & (průnik) vybere pouze znaky, které jsou v této třídě a třídě jiné. Pro definici třídy IsBracket, která má stejný význam jako IsZavorka stačí psát toto:

  sub IsBracket {
      return <<END
  +main::IsZavorka
  END
  }

Další možností definice unicode tříd je podle typu písma. Existují například třídy InHebrew, InMathematicalOperators. Celý seznam je na manuálové stránce perlunicode.

Zdroje

Toto téma by zabralo několik samostatných článků. Mnohem více o unicode třídách a jejich definicích na manuálových stránkách

  • man perlretut
  • man perlunicode.

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ů

28.11.2018 23:56 /František Kučera
Prosincový sraz spolku OpenAlt se koná ve středu 5.12.2018 od 16:00 na adrese Zikova 1903/4, Praha 6. Tentokrát navštívíme organizaci CESNET. Na programu jsou dvě přednášky: Distribuované úložiště Ceph (Michal Strnad) a Plně šifrovaný disk na moderním systému (Ondřej Caletka). Následně se přesuneme do některé z nedalekých restaurací, kde budeme pokračovat v diskusi.
Komentářů: 1

12.11.2018 21:28 /Redakce Linuxsoft.cz
22. listopadu 2018 se koná v Praze na Karlově náměstí již pátý ročník konference s tématem Datová centra pro business, která nabídne odpovědi na aktuální a často řešené otázky: Jaké jsou aktuální trendy v oblasti datových center a jak je optimálně využít pro vlastní prospěch? Jak si zajistit odpovídající služby datových center? Podle jakých kritérií vybírat dodavatele služeb? Jak volit vhodné součásti infrastruktury při budování či rozšiřování vlastního datového centra? Jak efektivně datové centrum spravovat? Jak co nejlépe eliminovat možná rizika? apod. Příznivci LinuxSoftu mohou při registraci uplatnit kód LIN350, který jim přinese zvýhodněné vstupné s 50% slevou.
Přidat komentář

6.11.2018 2:04 /František Kučera
Říjnový pražský sraz spolku OpenAlt se koná v listopadu – již tento čtvrtek – 8. 11. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma umění a technologie, IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář

4.10.2018 21:30 /Ondřej Čečák
LinuxDays 2018 již tento víkend, registrace je otevřená.
Přidat komentář

18.9.2018 23:30 /František Kučera
Zářijový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 20. 9. 2018 od 18:00 v Radegastovně Perón (Stroupežnického 20, Praha 5). Tentokrát bez oficiální přednášky, ale zato s dobrým jídlem a pivem – volná diskuse na téma IoT, CNC, svobodný software, hardware a další hračky.
Přidat komentář

9.9.2018 14:15 /Redakce Linuxsoft.cz
20.9.2018 proběhne v pražském Kongresovém centru Vavruška konference Mobilní řešení pro business. Návštěvníci si vyslechnou mimo jiné přednášky na témata: Nejdůležitější aktuální trendy v oblasti mobilních technologií, správa a zabezpečení mobilních zařízení ve firmách, jak mobilně přistupovat k informačnímu systému firmy, kdy se vyplatí používat odolná mobilní zařízení nebo jak zabezpečit mobilní komunikaci.
Přidat komentář

12.8.2018 16:58 /František Kučera
Srpnový pražský sraz spolku OpenAlt se koná ve čtvrtek – 16. 8. 2018 od 19:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát jsou tématem srazu databáze prezentaci svého projektu si pro nás připravil Standa Dzik. Dále bude prostor, abychom probrali nápady na využití IoT a sítě The Things Network, případně další témata.
Přidat komentář

16.7.2018 1:05 /František Kučera
Červencový pražský sraz spolku OpenAlt se koná již tento čtvrtek – 19. 7. 2018 od 18:00 v Kavárně Ideál (Sázavská 30, Praha), kde máme rezervovaný salonek. Tentokrát bude přednáška na téma: automatizační nástroj Ansible, kterou si připravil Martin Vicián.
Přidat komentář

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

> Poslední diskuze

31.7.2023 14:13 / Linda Graham
iPhone Services

30.11.2022 9:32 / Kyle McDermott
Hosting download unavailable

13.12.2018 10:57 / Jan Mareš
Re: zavináč

2.12.2018 23:56 / František Kučera
Sraz

5.10.2018 17:12 / Jakub Kuljovsky
Re: Jaký kurz a software by jste doporučili pro začínajcího kodéra?

Více ...

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