Substituce a nahrazovani znaku


Perl umi provadet substituci zalozenou na pouziti regularnich retezcu. Substituce se provadi pomoci funkce s, ktere je podobna substituci ve vi editoru. Pro substituci se pouzije srovnavaci operator =~. Pokud je srovnavaci operator vynechan provadi se substituce na promenne $_.

Chcete-li nahradit vyskyt retezce london retezcem London v promenne $sentence pouzijte prikaz

$sentence =~ s/london/London/
Je-li retezec ulozeny v promenne $_, pak ma prikaz pro uvedenou nahradu tvar
s/london/London/
Vsimnete si, ze dva regularni retezce jsou obklopeny celkem tremi lomitky.

Prikaz vraci pocet provedenych substituci, v tomto pripade 0 (false) nebo 1 (true). Vyraz pro substituci je tedy mozne pouzit i jako podminku v prikazu if.


Volby

Uvedeny priklad nahradil pouze prvni vyskyt retezce, muzeme vsak pozadovat nahrazeni vsech vyskytu daneho retezce. Nahrazeni vsech vyskytu retezce provedeme tzv. globalni substituci, tj. za posledni lomitko pridame pismeno g:
s/london/London/g
opet je mozne pouzit promennou $_.
Prikaz vraci pocet provedenych substituci, tj. 0 (false) nebo cislo vetsi nez 0 (true).

Chceme-li nahradit vyskyt lOndon, lonDON, LoNDoN atd., retezcem London muzeme pouzit prikaz

s/[Ll][Oo][Nn][Dd][Oo][Nn]/London/g
Existuje vsak jednodussi zpusob, a to pouzit volbu i (pro "ignore case"). Prikaz
s/london/London/gi
provede globalni substituci s ignorovanim typu pismen (mala, velka).


Opakovane pouziti vyhledanych retezcu

Casto je potreba podretezec nalezeny na jednom miste v retezci opakovane pouzit (napr. vlozit) na jinem miste v retezci. Vyhledane podretezce jsou ukladany do promennych $1,...,$9. Tyto retezce mohou byt pouzity v danem RE (nebo substituci) pomoci specialnich RE znaku \1,...,\9. Napriklad
$_ = "Lord Whopper of Fibbing";
s/([A-Z])/:\1:/g;
print "$_\n";
nahradi kazde velke pismeno stejnym pismenem obklopenym z kazde strany dvojteckou. Vytiskne se tedy :L:ord :W:hopper of :F:ibbing. Promenne $1,...,$9 jsou read-only; neni mozne je modifikovat.

Dalsi priklad je priklad testovani

if (/(\b.+\b) \1/)
{
	print "Slovo $1 se opakuje\n";
}
Oznaci kazde opakujici se slovo. Kazde \b predstavuje hranici slova a znak .+ predstavuje libovolny neprazdny retezec, tedy \b.+\b predstavuje cokoli mezi dvemi hranicemi slova, tedy slovo. Pouzili jsme zavorky a obsah zavorek byl ulozen jako specialni znak \1. Tento slecialni znak muzeme pouzit v danem regularnim vyrazu. Ve zbytku programu muzeme pracovat s promennou $1, ktera ma stejny obsah jako specialni znak \1.

Nasledujici priklad vymeni prvni a posledni znak na radku. Radek je ulozeny v promenne $_

s/^(.)(.*)(.)$/\3\2\1/
Znaky^ a $ reprezentuji zacatek a konec radku. V \1 je ulozen prvni znak; v \2 je cokoli az do posledniho znaku, ktery je ulozen v \3. Cela radka je tedy nahrazena radkou s prohozenymi znaky \1 a \3.

Pri vyhledavani jsou naplneny i specialni read-only promenne $` a $& a $', ktere je mozne dale v programu pouzit. Promenne jsou naplneny nasledujicim zpusobem:
$` zacatek retezce, az do vyhledavaneho podretezce $& vyhledavany podretezec $' konec retezce od vyhledavaneho podretezce. Tedy pokud naplnime promennou $_ a provedeme uvedene vyhledani podretezce pp v promenne $_

$_ = "Lord Wopper of Fibbing";
/pp/;
jsou vsechny nasledujici vyrazy jsou pravdive: (Pripomenme, ze eq je retezcove porovnani.)
$` eq "Lord Wo";
$& eq "pp";
$' eq "er of Fibbing";

Pred vyhledavanim se provadi konverze promennych, ktere jsou pouzity uvnitr lomitek. Tedy prikaz

$search = "the";
s/$search/xxx/g;
nahradi kazdy vyskyt retezce the v promenne $_ retezcem xxx. Pokud chcete nahradit kazdy vyskyt retezce there, pak nezadavejte s/$searchre/xxx/, nebot by se nahrazovalo jmeno promenne $searchre jejim obsahem. Ale jmeno promenne uzavrete do slozenych zavorek, spravny prikaz tedy vypada
$search = "the";
s/${search}re/xxx/;


Nahrazovani znaku

Funkce tr umoznuje nahrazovat znak jinym znakem. Nasledujici prikaz nahradi v promenne $sentence kazdy znak a znakem e, kazdy znak b znakem d, a kazdy znak c znakem f.
$sentence =~ tr/abc/edf/
Prikaz vraci pocet provedenych nahrazeni. Je tedy mozne napriklad prikazem if testovat, zda se nahrazeni provedlo nebo ne.
if ( $sentence =~ tr/abc/edf/) {
   print "nahrazeni provedeno\n";
   }
   else {
   print "v retezci se nevyskytuji znaky abc\n";
   } 

Vetsina specialnich znaku pro RE se ve funkci tr nepouziva. Nasledujici priklad zjistuje pocet hvezdicek v promenne $sentence a zjistene cislo ulozi do promenne $count.

$count = ($sentence =~ tr/*/*/);
Pomlcka znamena znaky mezi explicitne uvedenymi znaky.
Priklad prevede obsah promenne $_ na velka pismena.
tr/a-z/A-Z/;


Cviceni

Priklad 5.
Posledni verze vaseho programu by mela pocitat radky souboru, ktere obsahuji jisty retezec. Upravte program tak, aby pocital radky, ktere obsahuji zdvojena pismena nebo obecne dva stejne znaky tesne za sebou. Upravte ho pote jeste tak, aby nalezeny zdvojeny znak uzavrel do zavorek. Reseni. Vypsana radka muze vypadat napr. takto: For example
23 Amp, James Wa(tt), 
Zkuste jeste tuto modifikaci: vsechny zdvojene znaky budou v zavorkach krome prvniho zdvojeneho znaku na radku.

Nakonec muzeme zkusit program modifikovar tak, aby vyhledavany retezec prebiral jako parametr z prikazoveho radku. Predpokladam ,ze se vas program jmenuje pocitadlo.pl. Spoustite jej napr. prikazem

perl pocitadlo.pl
Pokud program spustite s nekolika parametry prikazem
perl pocitadlo.pl prvni druhy atd
jsou tyto parametry ulozeny v poli @ARGV. Tedy v nasem pripade je v $ARGV[0] retezec prvni a v $ARGV[1] retezec druhy a v $ARGV[2] retezec atd. Upravte program tak, aby ocekaval jeden parametr a pocital pouze radky, na kterych se vyskytne retezec udany jako parametr. Retezec opet vyznacte na radce pouzitim zavorek.


Dalsi kapitola | Predchozi kapitola kapitola | Obsah