Substituce a nahrazování znaků


Perl umí provádět substituci založenou na použití regulárních řetězců. Substituce se provádí pomocí funkce s, které je podobná substituci ve vi editoru. Pro substituci se použije srovnávací operátor =~. Pokud je srovnávací operátor vynechán provádí se substituce na proměnné $_.

Chcete-li nahradit výskyt řetězce london řetězcem London v proměnné $sentence použijte příkaz

$sentence =~ s/london/London/
Je-li řetězec uložený v proměnné $_, pak má příkaz pro uvedenou náhradu tvar
s/london/London/
Všimněte si, že dva regulární řetězce jsou obklopeny celkem třemi lomítky.

Příkaz vrací počet provedených substitucí, v tomto případě 0 (false) nebo 1 (true). Výraz pro substituci je tedy možné použít i jako podmínku v příkazu if.


Volby

Uvedený příklad nahradil pouze první výskyt řetězce, můžeme však požadovat nahrazení všech výskytů daného řetězce. Nahrazení všech výskytů řetězce provedeme tzv. globální substitucí, tj. za poslední lomítko přidáme písmeno g:
s/london/London/g
opět je možné použít proměnnou $_.
Příkaz vrací počet provedených substitucí, tj. 0 (false) nebo číslo větší než 0 (true).

Chceme-li nahradit výskyt lOndon, lonDON, LoNDoN atd., řetězcem London můžeme použít příkaz

s/[Ll][Oo][Nn][Dd][Oo][Nn]/London/g
Existuje však jednodušší způsob, a to použít volbu i (pro "ignore case"). Příkaz
s/london/London/gi
provede globální substituci s ignorováním typu písmen (malá, velká).


Opakované použití vyhledaných řetězců

Často je potřeba podřetězec nalezený na jednom místě v řetězci opakovaně použít (např. vložit) na jiném místě v řetězci. Vyhledané podřetězce jsou ukládány do proměnných $1,...,$9. Tyto řetězce mohou být použity v daném RE (nebo substituci) pomocí speciálních RE znaků \1,...,\9. Například
$_ = "Lord Whopper of Fibbing";
s/([A-Z])/:\1:/g;
print "$_\n";
nahradí každé velké písmeno stejným písmenem obklopeným z každé strany dvojtečkou. Vytiskne se tedy :L:ord :W:hopper of :F:ibbing. Proměnné $1,...,$9 jsou read-only; není možné je modifikovat.

Další příklad je příklad testování

if (/(\b.+\b) \1/)
{
	print "Slovo $1 se opakuje\n";
}
Označí každé opakující se slovo. Každé \b představuje hranici slova a znak .+ představuje libovolný neprázdný řetězec, tedy \b.+\b představuje cokoli mezi dvěmi hranicemi slova, tedy slovo. Použili jsme závorky a obsah závorek byl uložen jako speciální znak \1. Tento sleciální znak můžeme použít v daném regulárním výrazu. Ve zbytku programu můžeme pracovat s proměnnou $1, která má stejný obsah jako speciální znak \1.

Následující příklad vymění první a poslední znak na řádku. Řádek je uložený v proměnné $_

s/^(.)(.*)(.)$/\3\2\1/
Znaky^ a $ reprezentují začátek a konec řádku. V \1 je uložen první znak; v \2 je cokoli až do posledního znaku, který je uložen v \3. Celá řádka je tedy nahrazena řádkou s prohozenými znaky \1 a \3.

Při vyhledávání jsou naplněny i speciální read-only proměnné $` a $& a $', které je možné dále v programu použít. Proměnné jsou naplněny následujícím způsobem:
$` začátek řetězce, až do vyhledávaného podřetězce $& vyhledávaný podřetězec $' konec řetězce od vyhledávaného podřetězce. Tedy pokud naplníme proměnnou $_ a provedeme uvedené vyhledání podřetězce pp v proměnné $_

$_ = "Lord Wopper of Fibbing";
/pp/;
jsou všechny následující výrazy jsou pravdivé: (Připomeňme, že eq je řetězcové porovnání.)
$` eq "Lord Wo";
$& eq "pp";
$' eq "er of Fibbing";

Před vyhledáváním se provádí konverze proměnných, které jsou použity uvnitř lomítek. Tedy příkaz

$search = "the";
s/$search/xxx/g;
nahradí každý výskyt řetězce the v proměnné $_ řetězcem xxx. Pokud chcete nahradit každý výskyt řetězce there, pak nezadávejte s/$searchre/xxx/, neboť by se nahrazovalo jméno proměnné $searchre jejím obsahem. Ale jméno proměnné uzavřete do složených závorek, správný příkaz tedy vypadá
$search = "the";
s/${search}re/xxx/;


Nahrazování znaků

Funkce tr umožňuje nahrazovat znak jiným znakem. Následující příkaz nahradí v proměnné $sentence každý znak a znakem e, každý znak b znakem d, a každý znak c znakem f.
$sentence =~ tr/abc/edf/
Příkaz vrací počet provedených nahrazení. Je tedy možné například příkazem if testovat, zda se nahrazení provedlo nebo ne.
if ( $sentence =~ tr/abc/edf/) {
   print "nahrazeni provedeno\n";
   }
   else {
   print "v retezci se nevyskytuji znaky abc\n";
   } 

Většina speciálních znaků pro RE se ve funkci tr nepoužívá. Následující příklad zjišťuje počet hvězdiček v proměnné $sentence a zjištěné číslo uloží do proměnné $count.

$count = ($sentence =~ tr/*/*/);
Pomlčka znamená znaky mezi explicitně uvedenými znaky.
Příklad převede obsah proměnné $_ na velká písmena.
tr/a-z/A-Z/;


Cvičení

Příklad 5.
Poslední verze vašeho programu by měla počítat řádky souboru, které obsahují jistý řetězec. Upravte program tak, aby počítal řádky, které obsahují zdvojená písmena nebo obecně dva stejné znaky těsně za sebou. Upravte ho poté ještě tak, aby nalezený zdvojený znak uzavřel do závorek. Řešení. Vypsaná řádka může vypadat např. takto: For example
23 Amp, James Wa(tt), 
Zkuste ještě tuto modifikaci: všechny zdvojené znaky budou v závorkách kromě prvního zdvojeného znaku na řádku.

Nakonec můžeme zkusit program modifikovar tak, aby vyhledávaný řetězec přebíral jako parametr z příkazového řádku. Předpokládám ,že se váš program jmenuje pocitadlo.pl. Spouštíte jej např. příkazem

perl pocitadlo.pl
Pokud program spustíte s několika parametry příkazem
perl pocitadlo.pl prvni druhy atd
jsou tyto parametry uloženy v poli @ARGV. Tedy v našem případě je v $ARGV[0] řetězec prvni a v $ARGV[1] řetězec druhy a v $ARGV[2] řetězec atd. Upravte program tak, aby očekával jeden parametr a počítal pouze řádky, na kterých se vyskytne řetězec udaný jako parametr. Řetězec opět vyznačte na řádce použitím závorek.


Další kapitola | Předchozí kapitola kapitola | Obsah