Svet Perlu: 2. časť / Regulárne výrazy

perl_logo.png Ako sme už v pr­vej čas­ti se­riá­lu načrt­li, ma­jo­rit­ná časť skrip­tov Per­lu je vy­ví­ja­ná pre pot­re­by spra­co­va­nia texto­vých in­for­má­cií, pre kto­ré Perl im­ple­men­tu­je ro­bus­tnú prog­ra­mo­vú pod­po­ru, kto­rej hlav­ná časť sú ru­ti­ny spra­cú­va­jú­ce a vy­hod­no­cu­jú­ce re­gu­lár­ne vý­ra­zy. Re­gu­lár­ne vý­ra­zy Per­lu sčas­ti dodr­žu­jú syn­tax unixové­ho prog­ra­mu eg­rep.

Čo je to re­gu­lár­ny vý­raz
Re­gu­lár­ny vý­raz je exak­tná de­fi­ní­cia šab­ló­ny re­ťaz­ca zna­kov, kto­rá slú­ži spo­loč­ne s po­rov­ná­va­ným re­ťaz­com ako vstup inter­pre­te­ra re­gu­lár­nych vý­ra­zov (ďa­lej v texte ozna­čo­va­né­ho ter­mí­nom auto­mat). Vý­sled­kom je­ho čin­nos­ti je lo­gic­ká 1 (prav­da) (vstup­ný re­ťa­zec spĺňa pod­mien­ky re­gu­lár­ne­ho vý­ra­zu) ale­bo lo­gic­ká 0 (nep­rav­da) (vstup­ný re­ťa­zec nespĺňa pod­mien­ky kla­de­né re­gu­lár­nym vý­ra­zom). De­fi­ní­cia pri­tom po­zos­tá­va z en­tít naz­va­ných ató­my, me­taz­na­ky, kvan­ti­fi­ká­to­ry.

Ató­my
Atóm je syn­ony­mum pre sa­mos­tat­ný znak ale­bo sku­pi­nu zna­kov. Atóm sa zho­du­je sám so se­bou. Preš­tu­duj­te si nas­le­du­jú­ci frag­ment kó­du (1), kto­ré­ho vý­sled­kom čin­nos­ti je vý­stup (2).

(1) fo­reach ("Examp­le", "This is Examp­le", "And this is not examp­le")
    {
        print "String \"$_\" match.\n" if /Examp­le/;
    }
(2) String "Examp­le" match.
    String "This is Examp­le" match.

Uve­de­ný frag­ment ob­sa­hu­je cyk­lus inter­ujú­ci na pr­vkoch jed­no­du­ché­ho zoz­na­mu, pri­čom pre kaž­dý pr­vok da­né­ho zoz­na­mu vy­hod­no­cu­je je­ho zho­du z re­gu­lár­nym vý­ra­zom „Examp­le“. Ako prav­di­vé bu­dú vy­hod­no­te­né všet­ky pr­vky zoz­na­mu ob­sa­hu­jú­ce pod­re­ťa­zec „Examp­le“. Ur­či­te ste pos­treh­li sku­toč­nosť, že auto­mat im­pli­cit­ne roz­li­šu­je ma­lé a veľ­ké pís­me­ná. Tú­to a ďal­šie vlas­tnos­ti auto­ma­tu je mož­né pos­tih­núť za­čle­ne­ním mno­ži­ny mo­di­fi­ká­to­rov ope­rá­to­rov, kvan­ti­fi­ká­to­rov a me­taz­na­kov re­gu­lár­nych vý­ra­zov.

Poz­nám­ka:
Po­rov­na­nie pou­ži­té vo frag­men­te (1) ope­ru­je nad im­pli­cit­nou pre­men­nou cyk­lu $_ a je ek­vi­va­len­tné s konštruk­ciou $_ =~ /Examp­le/.

Me­taz­na­ky
Me­taz­na­ky re­gu­lár­nych vý­ra­zov ma­jú to­tož­ný vý­znam, aký de­fi­nu­je eg­reb unixu (Tab. 1). Znak \ nas­le­do­va­ný me­taz­na­kom pre­vá­dza da­ný me­taz­nak na li­te­rár. A opač­ne, znak \ nas­le­do­va­ný li­te­rá­rom pre­vá­dza da­ný li­te­rár na me­taz­nak. Me­taz­na­ky je mož­né roz­de­liť do dvoch ka­te­gó­rií. Tou pr­vou sú me­taz­na­ky s de­fi­no­va­nou dĺžkou. Prík­la­dom mô­že byť me­taz­nak \n sub­sti­tuu­jú­ci dvo­ji­cu li­te­rá­ro­vých zna­kov CRLF. Dru­hú ka­te­gó­riu tvo­ria tzv. tvr­de­nia s ne­de­fi­no­va­nou, resp. nu­lo­vou dĺžkou. Prík­la­dom mô­že byť tvr­de­nie \b sub­sti­tuu­jú­ce hra­ni­cu slo­va. Me­taz­na­ky s nu­lo­vou dĺžkou bu­dú ďa­lej ozna­čo­va­né ter­mí­nom tvr­de­nia.

Tvr­de­nia ^ a $ im­pli­cit­ne za­ru­ču­jú v po­ra­dí po­rov­na­nie len na za­čiat­ku, resp. kon­ci po­rov­ná­va­né­ho re­ťaz­ca. Perl pri „sing­le-li­ne“ re­ťaz­coch ap­li­ku­je op­ti­ma­li­záč­né me­tó­dy pri vy­hod­no­co­va­ní. Spra­co­va­nie „mul­ti-li­ne“ re­ťaz­cov ako sé­rie sa­mos­tat­ných re­ťaz­cov vy­ža­du­je pou­ži­tie mo­di­fi­ká­to­ra /m ope­rá­to­ra re­gu­lár­ne­ho vý­ra­zu, pri kto­ré­ho pou­ži­tí zna­ky ^ a $ za­ru­ču­jú v po­ra­dí po­rov­na­nie na za­čiat­ku, resp. kon­ci kaž­dé­ho riad­ka. Dvo­ji­ca tvr­de­ní ^ a $ je fun­kčne ek­vi­va­len­tná s dvo­ji­cou \A a \Z. Star­šie prog­ra­my pou­ží­va­li prís­tup pre­de­fi­no­va­nia po­mo­cou $*, kto­rý sa v sú­čas­nej ver­zii Per­lu neod­po­rú­ča.

Me­taz­nak . im­pli­cit­ne sub­sti­tuu­je ľu­bo­voľ­ný znak ok­rem zna­ku \n. V prí­pa­de pou­ži­tia mo­di­fi­ká­to­ra /s ope­rá­to­ra re­gu­lár­nych vý­ra­zov je za­ru­če­né ko­rek­tné sprá­va­nie zna­ku \n. Mo­di­fi­ká­tor /s pre­de­fi­nu­je nas­ta­ve­nia $*. Me­taz­nak . sa čas­to pou­ží­va spo­loč­ne s kvan­ti­fi­ká­tor­mi poč­tu vý­sky­tu. Za­ují­ma­vým prík­la­dom je po­rov­na­nie (3).

Al­ter­na­tí­va je de­fi­no­va­ná po­mo­cou me­taz­na­ku |. Po­rov­na­nie (4) bu­de vy­hod­no­te­né ako prav­di­vé v prí­pa­de, že po­rov­ná­va­ný re­ťa­zec ob­sa­hu­je as­poň je­den pod­re­ťa­zec to­tož­ný s „Examp­le“ ale­bo „Samp­le“.

Frag­ment (5) pre­zen­tu­je kom­plexnej­ší prík­lad po­rov­na­nia s pou­ži­tím me­taz­na­kov zos­ku­pe­nia ató­mov re­gu­lár­ne­ho vý­ra­zu. Po­rov­na­nie bu­de vy­hod­no­te­né ako prav­di­vé pre kaž­dý re­ťa­zec ob­sa­hu­jú­ci as­poň je­den vý­skyt re­taz­ca „Look at “ nas­le­do­va­ný jed­ným z ató­mov „Examp­le“ ale­bo „Samp­le“. Zdru­žo­va­nie sa pou­ží­va pri pot­re­be spät­nej re­fe­ren­cie na da­ný atóm (poz­ri ďa­lej).

Ďal­ším z me­taz­na­kov je de­fi­ní­cia trie­dy zna­kov, kto­rá sa zho­du­je s ľu­bo­voľ­ným zna­kom z da­né­ho zoz­na­mu zna­kov uve­de­ným v hra­na­tých zá­tvor­kách de­fi­ní­cie trie­dy. Mo­di­fi­ká­tor ^ na za­čiat­ku zoz­na­mu ne­gu­je vý­sle­dok po­rov­na­nia. Pri de­fi­ní­cii trie­dy zna­kov je mož­né jed­not­li­vé zna­ky vy­me­no­vať ale­bo pou­žiť zá­pis ek­vi­va­lent­ný s (6).

Tvr­de­nie \b je de­fi­no­va­né ako di­era me­dzi dvo­ma znak­mi so zna­kom /w na jed­nej a /W na dru­hej stra­ne.

Pre­to­že sú re­gu­lár­ne vý­ra­zy spra­cú­va­né ako re­ťa­zo­vé li­te­rá­ry, je mož­né pou­ží­vať v konštruk­ciách re­gu­lár­nych vý­ra­zov všet­ky me­taz­na­ky li­te­rá­rov uve­de­né v pre­doš­lej čas­ti se­riá­lu. Perl ďa­lej de­fi­nu­je špe­ciál­nu trie­du me­taz­na­kov, slú­žia­cich ako sub­sti­tú­cia čas­to pou­ží­va­ných konštruk­cií iných me­taz­na­kov (tab. 2).

(3) /Ti­me: (..):(..):(..) (AM|PM)/
(4) /Examp­le|Samp­le/
(5) /Look at (Examp­le|Samp­le)/
(6) /[a-zA-Z]/

Tab. 1 Me­taz­na­ky re­gu­lár­nych vý­ra­zov

Me­taz­nak	Opis
\		uve­de­nie nas­le­du­jú­ce­ho me­taz­na­ku ako li­te­rá­ru, resp. uve­de­nie nas­le­du­jú­ce­ho li­te­rá­ru ako me­taz­na­ku
^		po­rov­na­nie na za­čiat­ku re­ťaz­ca, resp. riad­ka pri ap­li­ká­cíi na „mul­ti-li­ne buf­fer“ s mo­di­fi­ká­to­rom /m
$		po­rov­na­nie na kon­ci re­ťaz­ca, resp. riad­ka pri ap­li­ká­cii na „mul­ti-li­ne buf­fer“ s mo­di­fi­ká­to­rom /m
.		sub­sti­tú­cia ľu­bo­voľ­né­ho zna­ku ok­rem zna­ku \n
|		al­ter­na­tí­va
()		zos­ku­pe­nie zna­kov
[]		de­fi­ní­cia trie­dy zna­kov
\A		fun­kčne ek­vi­va­len­tné s ^
\b		hra­ni­ca slo­va
\B		ne­gá­cia \b
\G		zho­du­je sa tam, kde sa skon­či­lo m//g
\Z		fun­kčne ek­vi­va­len­tné s $

Tab. 2 Sub­sti­tuč­né me­taz­na­ky

Me­taz­nak	Opis
\d		nu­me­ric­ký znak ([0-9])
\D		nie nu­me­ric­ký znak ([^0-9])
\s		„whi­te spa­ce“ znak ([\t\n\r\f])
\S		nie „whi­te spa­ce“ znak ([^\t\n\r\f])
\w		al­fa­nu­me­ric­ký znak slo­va ([a-zA-Z ])
\W		nie al­fa­nu­me­ric­ký znak ([^a-zA-Z ])

Kvan­ti­fi­ká­to­ry
Pou­ži­tie kvan­ti­fi­ká­to­rov umož­ňu­je de­fi­no­vať kvan­tum da­né­ho ató­mu. Iný­mi slo­va­mi, atóm nas­le­do­va­ný kvan­ti­fi­ká­to­rom sa mu­sí zho­do­vať toľ­kok­rát, koľ­kok­rát to de­fi­nu­je prís­luš­ný kvan­ti­fi­ká­tor. Kvan­ti­fi­ká­to­ry re­gu­lár­nych vý­ra­zov sú uve­de­né v tab. 3. Ľavý stĺpec de­fi­nu­je syn­tax pre tzv. „hlad­né“ (v an­glic­kej li­te­ra­tú­re ozna­čo­va­né ter­mí­nom „Gree­dy“) kvan­ti­fi­ká­to­ry, pri kto­rých pou­ži­tí sa auto­mat po­kú­ša náj­sť naj­dlh­šiu zho­du. Pri vy­hod­no­co­va­ní re­gu­lár­ne­ho vý­ra­zu frag­men­tu (7) auto­mat hľa­dá naj­dl­hší re­ťa­zec nas­le­do­va­ný ató­mom „no“. Vý­sle­dok hľa­da­nia je vy­jad­re­ný (8).
Po­kiaľ re­gu­lár­ny vý­raz (7) up­ra­ví­me na tvar (9), auto­mat bu­de, nao­pak, hľa­dať naj­krat­ší re­ťa­zec nas­le­do­va­ný ató­mom „no“ (10). Kom­plexnej­ším prík­la­dom je (11), pri kto­ré­ho vy­hod­no­co­va­ní hľa­dá auto­mat naj­dl­hší re­ťa­zec po­zos­tá­va­jú­ci z ató­mov „yes“, „no“ a „ “, za­čí­na­jú­ci pr­vým vý­sky­tom „yes“ a ukon­če­ný „no“. Vý­stup vy­jad­ru­je (12).
Pa­ra­met­re „Cur­ly“ kvan­ti­fi­ká­to­rov ({n}, {n,}, {n,m}) sú ty­pu 16bit un­sig­ned in­te­ger, z čo­ho vy­plý­va po­vo­le­ný roz­sah hod­nôt z inter­va­lu <0, 65535>.

Poz­nám­ka:
Pre­men­né $1, $2 … sú špe­ciál­ne pre­men­né Per­lu, kto­ré v kon­texte s re­gu­lár­ny­mi vý­raz­mi sú po vy­hod­no­te­ní ope­rá­cie po­rov­na­nia auto­ma­tom ini­cia­li­zo­va­né hod­no­ta­mi spät­ných re­fe­ren­cií na zos­ku­pe­nia. Konštruk­cia (?: re­gu­la­rExpres­sion) má rov­na­kú fun­kciu ako (re­gu­la­rEexpres­sion), pri­čom ne­ge­ne­ru­je spät­né re­fe­ren­cie. Pod­rob­nej­šie vy­svet­le­nie náj­de či­ta­teľ ďa­lej.

(7)  "foo yes no yes no yes no yes no" =~ /(.*)no/;
     print "$1\n";
(8)  foo yes no yes no yes no yes

(9)  "foo yes no yes no yes no yes no" =~ /(.*?)no/;
     print "$1\n";
(10) foo yes

(11) "foo yes no yes no yes no yes no yes no yes foo" =~ /(.*?)yes((?:yes|no| )*)no(.*)/;
     print "$1\"yes\"$2\"no\"$3";
(12) foo "yes" no yes no yes no yes no yes "no" yes foo

Tab. 3 Kvan­ti­fi­ká­to­ry re­gu­lár­nych vý­ra­zov

„Gree­dy“	„Gra­vi­ty“	Opis
*		*?		0 ale­bo viac­krát (ek­vi­va­len­tné s {0,}, resp. {0,}?)
+		+?		as­poň raz ale­bo viac­krát (ek­vi­va­len­tné s {1,}, resp. {1,}?)
?		??		0 ale­bo raz (ek­vi­va­len­tné s {0,1}, resp. {0,1}?)
{n}		{n}?		pres­ne n-krát
{n,}		{n,}?		as­poň  n-krát
{n,m}		{n,m}?	as­poň n-krát, ale me­nej než (m+1)-krát

Roz­ší­re­ná syn­tax Perl 5
Perl 5 im­ple­men­tu­je roz­ší­re­nú syn­tax re­gu­lár­nych vý­ra­zov za­ve­de­ním konštruk­cie dvo­ji­ce ok­rúh­lych zá­tvo­riek so zna­kom “?” na pr­vom mies­te te­la nas­le­do­va­ným zna­kom iden­ti­fi­ká­cie roz­ší­re­nia. Perl 4 vy­hod­no­cu­je da­né konštruk­cie ako syn­taxovú chy­bu.

Konštruk­cia (13) uvá­dza ko­men­tár v te­le re­gu­lár­ne­ho vý­ra­zu. Pri pou­ži­tí mo­di­fi­ká­to­ra /x ope­rá­to­ra re­gu­lár­ne­ho vý­ra­zu je pos­ta­ču­jú­ci znak #.

(13) (?#com­ment)

V texte už pou­ži­tá konštruk­cia (14) je fun­kčne ek­vi­va­len­tná s konštruk­ciou zos­ku­pe­nia zna­kov, pri­čom ne­ge­ne­ru­je spät­né re­fe­ren­cie. Pre­to sú frag­men­ty (15) a (16) fun­kčne ek­vi­va­len­tné. Pri­tom po vy­ko­na­ní po­rov­na­nia (16) nie je ini­cia­li­zo­va­ná pre­men­ná $1.

(14) (?:re­gu­la­rExpres­sion)
(15) if ("#!…" =~ /^#(?:!|\?)/) { … }
(16) if ("#!…" =~ /^#(!|\?)/) { … }

Konštruk­cia (17) rep­re­zen­tu­je tvr­de­nie poh­ľa­du dop­re­du (loo­ka­head). Po­rov­na­nie (18) hľa­dá re­ťa­zec „Piz­za“ nas­le­do­va­ný re­ťaz­com „Hut“.

(17) (?=re­gu­la­rExpres­sion)
(18) /Piz­za(?=\sHut\b)/

Konštruk­cia (17) sa nie­ke­dy ozna­ču­je aj ako po­zi­tív­ne tvr­de­nie poh­ľa­du dop­re­du. Ďalej je im­ple­men­to­va­né roz­ší­re­nie ne­ga­tív­ne­ho tvr­de­nia dop­re­du (19). Po­rov­na­nie (20) hľa­dá re­ťa­zec “Piz­za”, kto­rý nie je nas­le­do­va­ný re­ťaz­com “Hut”.

(19) (?!re­gu­la­rExpres­sion)
(20) /Piz­za(?!\sHut\b)/

Prog­ra­má­to­ri Per­lu si čas­to pri čí­ta­ní do­ku­men­tá­cie vy­tvá­ra­jú dom­nien­ku ek­vi­va­len­cie ter­mí­nov “Loo­ka­head” a “Look­be­hind” (poh­ľad dop­re­du a poh­ľad do­za­du). Čas­to sa vy­sky­tu­jú chy­by ty­pu (21). Da­né po­rov­na­nie neh­ľa­dá zho­du re­ťaz­ca „Hut“, pred kto­rým nes­to­jí re­ťa­zec „Piz­za“. Je pot­reb­né po­cho­piť roz­diel me­dzi ato­már­nou jed­not­kou (ató­mom) a tvr­de­ním, kto­ré je cha­rak­te­ri­zo­va­né len svo­jou prav­di­vos­ťou, a nie dĺžkou.

(21) /(?!\bPiz­za\s) Hut/

Pos­led­nou roz­ši­ru­jú­cou konštruk­ciou, o kto­rej sa mô­že­te v ma­nuá­lo­vých strán­kach Per­lu do­čí­tať, je mož­nosť vkla­da­nia mo­di­fi­ká­to­rov ope­rá­to­rov re­gu­lár­nych vý­ra­zov pria­mo do te­la re­gu­lár­ne­ho vý­ra­zu (22). Frag­men­ty (23) a (24) sú fun­kčne ek­vi­va­len­tné.

(22) (?imsx)
(23) $so­me­Re­gu­la­rExpres­sion = “foo”;
     /$so­me­Re­gu­la­rExpres­sion/i
(24) $so­me­Re­gu­la­rExpres­sion = “(?i)foo”;
     /$so­me­Re­gu­la­rExpres­sion/

Spät­né re­fe­ren­cie
Spät­né re­fe­ren­cie slú­žia na zís­ka­nie ob­sa­hu konštruk­cií zos­ku­pe­nia. Vo vnút­ri te­la re­gu­lár­ne­ho vý­ra­zu sa pou­ží­va zá­pis (25), kde di­git je po­ra­do­vé čís­lo zos­ku­pe­nia. Pek­ným prík­la­dom z ma­nuá­lo­vých strá­nok Per­lu je po­rov­na­nie (26), kto­ré sa zho­du­je pre dve to­tož­né slo­vá od­de­le­né zna­kom = (nap­rík­lad foo = foo). Čas­to sa vy­sky­tu­jú chy­by pri pou­ží­va­ní spät­ných re­fe­ren­cií s in­dexmi väč­ší­mi než 9. Da­ná re­fe­ren­cia je v prí­pa­de, že pred ňou nes­to­jí zod­po­ve­da­jú­ce množ­stvo konštruk­cií zos­ku­pe­nia, kvô­li spät­nej kom­pa­ti­bi­li­te vy­hod­no­te­ná ako \0di­git (t.j. znak vy­jad­re­ný ok­ta­no­vo).

Pre ope­rá­to­ry re­gu­lár­nych vý­ra­zov sú dô­le­ži­té von­kaj­šie spät­né re­fe­ren­cie so syn­taxu (27), kde di­git je fun­kčne ek­vi­va­lent­ný so zá­pi­som (25). Prík­la­dom mô­že byť zme­na po­ra­dia pr­vých dvoch slov (28).

(25) /di­git
(26) /(\w+)\s*=\s*\1/
(27) $di­git
(28) s/^(\w+)(\s+)(\w+)/$3$2$1/

Ope­rá­to­ry re­gu­lár­nych vý­ra­zov
Toľ­ko teória, prax vy­ža­du­je ap­li­ko­va­nie ope­rá­to­rov re­gu­lár­nych vý­ra­zov, čo vy­svet­ľu­jú nas­le­du­jú­ce od­se­ky.

Ope­rá­tor po­rov­na­nia
V pre­doš­lých prík­la­doch čas­to pou­ží­va­ným ope­rá­to­rom je ope­rá­tor po­rov­na­nia (29). Ope­rá­tor po­rov­na­nia, ope­ru­jú­ci im­pli­cit­ne nad pre­men­nou $_, hľa­dá zho­du s de­fi­no­va­ným vzo­rom pat­tern. Ope­rá­tor je mož­né ap­li­ko­vať na ľu­bo­voľ­ný ska­lár po­mo­cou dvo­ji­ce nad­vä­zo­va­cích ope­rá­to­rov =~ a !~.
Ako oh­ra­ni­ču­jú­ce zna­ky je mož­né pou­žiť ľu­bo­voľ­né neal­fa­nu­me­ric­ké a nie „whi­te-spa­ce“ zna­ky, čo de­monštru­je frag­ment (29). Po­čia­toč­ný znak m je v prí­pa­de pou­ži­tia oh­ra­ni­ču­jú­cich zna­kov / ne­po­vin­ný. Pri náj­de­ní zho­dy sú vý­sled­kom ope­rá­cie po­rov­na­nia v kon­texte zoz­na­mu hod­no­ty zod­po­ve­da­jú­cich konštruk­cií zos­ku­pe­nia, resp. pri ich ab­sen­cii zoz­nam o hod­no­te „1“. V opač­nom prí­pa­de je vrá­te­ný nu­lo­vý zoz­nam.

(29) $re­fe­rer = ‘yahoo.com’;
     if ($ENV{'HTTP_RE­FE­RER'} =~ m|https?://([^/]*)$re­fe­rer|i) { … }

Vlas­tnos­ti po­rov­ná­va­nia je mož­né ov­plyv­niť mno­ži­nou mo­di­fi­ká­to­rov (tab. 4).

Mo­di­fi­ká­tor /g vy­nu­cu­je vy­hľa­da­nie všet­kých mož­ných zhôd. Pri náj­de­ní zho­dy sú po­tom vý­sled­kom ope­rá­cie po­rov­na­nia v kon­texte zoz­na­mu hod­no­ty zod­po­ve­da­jú­cich konštruk­cií zos­ku­pe­nia, resp. pri ich ab­sen­cii všet­ky zho­dy. Preš­tu­duj­te si frag­men­ty (30) a (32) a ich zod­po­ve­da­jú­ce vý­stu­py (31) a (33). V ska­lár­nom kon­texte ope­rá­tor inter­uje nad da­ným re­ťaz­com a vra­cia lo­gic­kú 1 v prí­pa­de, že bo­la náj­de­ná zho­da, pri­čom si pa­mä­tá, na kto­rej po­zí­cii bo­lo pre­ru­še­né preh­ľa­dá­va­nie, je mož­né zis­tiť ju vo­la­ním fun­kcie pos(). Pri zme­ne hod­no­ty preh­ľa­dá­va­né­ho re­ťaz­ca je tá­to po­zí­cia nas­ta­ve­ná na vý­cho­dis­ko­vú. Frag­ment (34) kal­ku­lu­je po­čet slov v $foo.

(29) m/pa­tern/gi­mosx
(30) $foo="foo 123 bar 321";
     @re­turnList  = ( $foo =~ m/([a-zA-Z]+)\s+([0-9]+)/g );
     fo­reach (@re­turnList) { print "${_} " }
(31) foo 123 bar 321
(32) $foo="I lo­ve Piz­za Hut ...";
     @re­turnList = ( $foo =~ m/[a-zA-Z]+/g );
     fo­reach (@re­turnList) { print "${_} " }
(33) I lo­ve Piz­za Hut
(34) $coun­ter = 0;
     $foo="I lo­ve Piz­za Hut";
     whi­le ( $foo =~ m/\b[a-zA-Z]+\b/g ) { $coun­ter++ }
     print "$coun­ter";

Mo­di­fi­ká­tor /o vy­nu­cu­je je­di­nú kom­pi­lá­ciu vzo­ru. Pri je­ho pou­ži­tí nes­mie byť hod­no­ta vzo­ru po je­ho pr­vom vy­hod­no­te­ní mo­di­fi­ko­va­ná (35).

(35) $foo = “bar”;
     if /$foo/ { … #od te­raz nie je mož­né mo­di­fi­ko­vať hod­no­tu ska­lá­ru $foo 
     }

Tab. 4 Mo­di­fi­ká­to­ry ope­rá­to­ra po­rov­na­nia

Mo­di­fi­ká­tor	Opis
g		vy­hľa­da­nie všet­kých zhôd (match glo­bal­ly)
i		ne­roz­li­šuj ma­lé a veľ­ké pís­me­ná (ca­se in­sen­si­ve)
m		spra­co­va­nie re­ťaz­ca ako „mul­ti-li­ne buf­fer“
o		vy­nú­te­nie je­di­nej kom­pi­lá­cie
s		spra­co­va­nie re­ťaz­ca ako „sig­le-li­ne“

Ope­rá­tor sub­sti­tú­cie
Ope­rá­tor sub­sti­tú­cie (36) je syn­tak­tic­ky po­dob­ný ope­rá­to­ru po­rov­na­nia, pri­čom vy­ko­ná­va sub­sti­tú­ciu re­ťaz­cov vy­ho­vu­jú­cich vzo­ru pat­tern za re­ťa­zec rep­la­ce­ment. Ope­rá­tor vra­cia ako vý­sle­dok vo­la­nia po­čet vy­ko­na­ných sub­sti­tú­cií. Ope­rá­tor im­pli­cit­ne ope­ru­je nad pre­men­nou $_. Je mož­né pou­žiť nad­vä­zo­va­cie ope­rá­to­ry =~ a !~.
Ako oh­ra­ni­ču­jú­ce zna­ky je mož­né pou­žiť ľu­bo­voľ­né neal­fa­nu­me­ric­ké a nie „whi­te-spa­ce“ zna­ky, pre pat­tern a rep­la­ce­ment (37).
Hod­no­ta pa­tern je vy­hod­no­te­ná na za­čiat­ku vy­ko­ná­va­nia sub­sti­tú­cií. Nao­pak, hod­no­ta rep­la­ce­ment je vy­hod­no­co­va­ná po vy­ko­na­ní kaž­dej sub­sti­tú­cie.
Ope­rá­tor pou­ží­va roz­ší­re­nú mno­ži­nu mo­di­fi­ká­to­rov ope­rá­to­ra po­rov­na­nia o mo­di­fi­ká­tor /e, vy­nu­cu­jú­ci inter­pre­tá­ciu rep­la­ce­ment ako pl­no­hod­not­né­ho vý­ra­zu. Prík­la­dy ope­rá­to­ra sub­sti­tú­cie (28) a (38).

(36) s/pat­tern/rep­la­ce­ment/egi­mosx
(37) s(pat­tern)(rep­la­ce­ment)
     s(pat­tern)
(38) #de­kó­do­va­nie pa­ra­met­rov pre­da­ných me­tó­dou GET CGI pro­ce­su
     $va­lue =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

Špe­ciál­ne pre­men­né
Tá­to časť ob­jas­ní ta­jom­né pre­men­né Per­lu v kon­texte s re­gu­lár­ny­mi vý­raz­mi.

$_ je pre­men­nou, nad kto­rou im­pli­cit­ne ope­ru­jú nie­len ope­rá­to­ry re­gu­lár­nych vý­ra­zov. Po­rov­na­nia (39) a (40) sú fun­kčne ek­vi­va­len­tné.

(39) /foo/
(40) $_ =~ /foo/

$di­git je spät­ná re­fe­ren­cia na zos­ku­pe­nie s po­ra­do­vým čís­lom di­git.
$&($MATCH)- zho­du­jú­ci sa re­ťa­zec pos­led­né­ho po­rov­na­nia (read-on­ly) (41).
$' ($PRE­MATCH) - re­ťa­zec, kto­rý je nas­le­do­va­ný zho­du­jú­cim sa re­ťaz­com pos­led­né­ho po­rov­na­nia (read-on­ly) (41).
$’ ($POS­TMATCH) - nas­le­du­jú­ci re­ťa­zec za zho­du­jú­cim sa re­ťaz­com pos­led­né­ho po­rov­na­nia (read-on­ly). Ver­bál­ny opis pos­led­nej tro­ji­ce mô­že byť za­vá­dza­jú­ci, pre­to si preš­tu­duj­te frag­ment (41) a je­ho zod­po­ve­da­jú­ci vý­stup (42).

(41) $foo = “123456”;
     $foo =~ /34/;
     print “$'-$&-$’”;
(42) 12-34-56
$+ ($LAST_PA­REN_MATCH) - hod­no­ta pos­led­né­ho zos­ku­pe­nia (read-on­ly).
$* ($MUL­TI­LI­NE_MAT­CHING) - ini­cia­li­zá­cia hod­no­tou 1 vy­nu­cu­je vy­hod­no­co­va­nie ope­ran­dov ope­rá­to­rov re­gu­lár­nych vý­ra­zov ako “mul­ti-li­ne buf­fer”, resp. pri nu­lo­vej hod­no­te “sing­le-li­ne”. V sú­čas­nej ver­zii Per­lu sa neod­po­rú­ča pou­ži­tie tej­to pre­men­nej a jej fun­kcio­na­li­ta je dodr­ža­ná kvô­li spät­nej kom­pa­ti­bi­li­te.

Backtrac­king
Inter­pre­ter re­gu­lár­nych vý­ra­zov je ne­de­ter­mi­nis­tic­ký ko­neč­ný auto­mat. To zna­me­ná, že prin­cí­pom je­ho čin­nos­ti je backtrac­king. Po­cho­pe­nie tej­to čas­ti je ne­vyh­nut­né na nes­kor­šie pou­ží­va­nie re­gu­lár­nych vý­ra­zov. Na ob­jas­ne­nie ter­mí­nu backtrac­king pou­ži­je­me po­rov­na­nie (43). V ur­či­tom oka­mi­hu inter­pre­tá­cie je náj­de­ná zho­da ató­mu atom1 na po­zí­cii n, tvr­de­nie as­sertion1 je prav­di­vé a bo­la vy­hod­no­te­ná 3-ná­sob­ná zho­da ató­mu atom2. Auto­mat ďa­lej pok­ra­ču­je vy­hod­no­te­ním tvr­de­nia as­sertion2. Po­kiaľ bu­de vy­hod­no­te­né ako nep­rav­di­vé, auto­mat zní­ži ná­sob­nosť zho­dy ató­mu atom2 o jed­nu a pok­ra­ču­je ďa­lej vy­hod­no­te­ním tvr­de­nia2. Po­kiaľ bu­de nep­rav­di­vé, opa­ku­je cyk­lus zni­žo­va­nia ná­sob­nos­ti na mi­ni­mál­nu hod­no­tu (v na­šom prí­pa­de 0), a ak opäť bu­de tvr­de­nie as­sertion2 nep­rav­di­vé, zvý­ši hod­no­tu in­dexu iden­ti­fi­ku­jú­ce­ho of­fset od za­čiat­ku re­ťaz­ca (v na­šom prí­pa­de n--) a ce­lý pro­ces opa­ku­je. Iný­mi slo­va­mi, auto­mat sa sna­ží za kaž­dú ce­nu náj­sť zho­du. Po­zor, auto­mat neh­ľa­dá naj­lep­šiu zho­du, čo de­monštru­jú po­rov­na­nia frag­men­tu (44), kto­ré neh­ľa­da­jú naj­dlh­šiu zho­du. Po­dob­ne ako pr­vé dve po­rov­na­nia (46) ko­rek­tne nei­zo­lu­jú pos­led­né čís­lo v re­ťaz­ci.

(43) /atom1as­sertion1(atom2*)as­sertion2atom­3ass­ert­ion­3/

(44) $foo = "123 abc 1234 abcd 12345 ab­cdef";
     print "/([a-z]*)/ match \"$1\"\n" if $foo =~ /([a-z]*)/;
     print "/([a-z]+)/ match \"$1\"\n" if $foo =~ /([a-z]+)/;
(45) /([a-z]*)/ match ""
     /([a-z]+)/ match "abc"

(46) print "/(.*)(\\d*)$/ match \"$1\" and \"$2\"\n" if "abc 123" =~ /(.*)(\d*)$/;
     print "/(.*)(\\d+)$/ match \"$1\" and \"$2\"\n" if "abc 123" =~ /(.*)(\d+)$/;
     print "/(\\D*)(?=\\d)(\\d*)$/ match \"$1\" and \"$2\"\n" if "abc 123" =~ /(\D*)(?=\d)(\d*)$/;
(47) /(.*)(\d*)$/ match "abc 123" and ""
     /(.*)(\d+)$/ match "abc 12" and "3"
     /(\D*)(?=\d)(\d*)$/ match "abc " and "123"

S vy­pä­tím síl…
Re­gu­lár­ne vý­ra­zy sú jed­ným z dô­vo­dov, pre­čo sa Perl čas­to ozna­ču­je ako ja­zyk „len na zá­pis“. Ne­zried­ka sa stá­va ana­lý­za niek­to­rých konštruk­cií re­gu­lár­nych vý­ra­zov aj pre skú­se­né­ho prog­ra­má­to­ra Per­lu po­mer­ne kom­pli­ko­va­nou. Na zá­ver az­da len ci­tát Larry­ho Wal­la: „Re­gu­lár­ny vý­raz je to, bez čo­ho sa ne­dá prog­ra­mo­vať. Te­da ak to po­cho­pí­te…“

Na­bu­dú­ce
De­fi­ní­cia pod­prog­ra­mov a všet­ké­ho, čo s ni­mi sú­vi­sí.

Kam by ste sa ma­li ísť po­zrieť
http://www.perl.org
http://lan­gua­ge.perl.com/all_about/re­gexps.html

Kam by ste sa moh­li ísť po­zrieť
http://in­fo.pvt.net/perl/perl.htm
http://www.cre.ca­non.co.uk/~neilb//perl/VHLL/sli­de01.html
http://www.mit.edu:8001/perl/perl.html


Ďal­šie čas­ti >>

Zdroj: PC Revue 2/1998



Ohodnoťte článok:
   
 

24 hodín

týždeň

mesiac

Najnovšie články

Svet Per­lu: 3. časť / Re­fe­ren­cie a po­dprog­ra­my
Jedným zo závažných nedostatkov Perlu bola donedávna absencia podpory komplexných dátových štruktúr podobných pascalovským záznamom alebo štruktúram jazyka C. čítať »
 
Svet Per­lu: 2. časť / Re­gu­lár­ne vý­ra­zy
Ako sme už v prvej časti seriálu načrtli, majoritná časť skriptov Perlu je vyvíjaná pre potreby spracovania textových informácií, pre ktoré Perl implementuje čítať »
 
Svet Per­lu: 1. časť / Za­čí­na­me
Perl (Practical Extraction and Reporting Language) vytvoril v roku 1986 systémový programátor Larry Wall pre potreby riadenia a správy konfigurácie systémov Unix. čítať »
 
 
 
  Zdieľaj cez Facebook Zdieľaj cez Google+ Zdieľaj cez Twitter Zdieľaj cez LinkedIn Správy z RSS Správy na smartfóne Správy cez newsletter