|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Menu
Distributions (131)
Software (10844)
|
Perl (21) - Regulární výrazy - nahrazováníDo této chvíle jsme regulární výrazy používali pouze k vyhledávání. To je ale jen polovina toho, co skutečně dokáží.
Jak již o regulárních výrazech víme, slouží nejen pro vyhledávání vzorů, ale také pro nahrazování jejich částí. Představme si, že máme nějaký textový řetězec a potřebujeme z něj vymazat všechna čísla. Už známe několik způsobů, jak tento problém řešit. Celý řetězec by se dal rozdělit na znaky a každý získaný znak porovnat s možnými číslicemi. Další možností je rozdělit řetězec funkcí split s číselným oddělovačem. Nicméně to je všechno zbytečně pracné. Regulární výrazy mají pro takové případy další možnou syntaxi. Chceme-li nahrazovat, použití regulárního výrazu se s prostým vyhledáváním v několika detailech liší. V zápisu se místo úvodního m používá s a jeho uvedení je povinné. Následuje vzor a řetězec, kterým bude úsek vyhovující vzoru nahrazen. Protože zde je o položku více, je třeba oddělovač navíc.
s/vzor/náhrada/
Ač je zřejmé, že tomu nemůže být jinak, podotkněme, že náhrada je vždy prostým řetězcem a nikoliv regulárním výrazem. V diskuzních fórech se dnes a denně setkáváme s reakcemi typu
s/nabýdku/nabídku/
To je právě ukázka nahrazení, jen bez využití regulárních výrazů. Autor takového příspěvku dává na vědomí, že pisatel udělal pravopisnou chybu a měla by být opravena. Tímto způsobem bychom opravu řešili v Perlu:
$reakce = "Takovou nabýdku nebudu komentovat..."; I kdyby bylo v řetězci více stejných chyb, opraví se jen jedna z nich. Vždy se nahrazuje pouze 1. výskyt. Po jeho nalezení totiž vyhledávání vzoru skočí úspěchem. Náš problém, kdy jsme chtěli z řetězce odstranit všechna čísla, by se dal řešit uvedením přepínače g. Ten se, podobně jako u vyhledávání, aplikuje na všechny výskyty vyhovující vzoru v řetězci. Výskyty tedy budeme nahrazovat prázdným řetězcem.
$retezec = "P21E251215563R413215305711L587"; Jednoduché nahrazování - konverze znakůTato problematika do regulárních výrazů nepatří, ale má s nimi některé společné rysy. Z tohoto důvodu je zařazena právě zde. Činnost této konstrukce není nic jiného, než nahrazování konkrétního znaku (nikoliv regulárního výrazu) za jiný konkrétní znak. Syntaxe je podobná jako při nahrazování u regulárních výrazů:
$text =~ tr/abc/ABC/; y a tr jsou 2 synonymní zápisy. Po vykonání libovolného ze zmíněných tří příkazů se obsah proměnné $text změní. Všechna a se nahradí za A, všechna b za B a všechna c za C. Obecně se tedy ntý znak na levé straně nahrazuje ntým znakem z pravé strany. Rozdíl mezi použitím !~ nebo =~ je v návratové hodnotě. Výraz s !~ vrací true, pokud nedošlo k žádnému nahrazení. Pokud ano, vrací false. !~ se u tr příliš nepoužívá. Naproti tomu =~ vrací vždy počet nahrazení. Pokud je tento počet nenulový, návratová hodnota je tedy true. I u tr fungují rozsahy. Není tak problémem v proměnné $text nahradit všechna malá písmena za velká, bez toho abychom je všechny vypisovali (pomiňme použití funkce uc):
$text =~ tr/a-z/A-Z/; Teď si objasníme sporné případy použití tr:
$text = "ABCDEF"; Jako ukázku si nemohu odpustit Caesarovu šifru (v Unixu příkazy caesar, rot13). Jde o to nahradit každý znak (písmeno) znakem, který je v abecedě (ASCII tabulce, nebo zkrátka v nějaké soustavě znaků) o určitý počet znaků dále nebo blíže. Poprvé tuto šifru použili ke komunikaci Caesar a Cicero v době galské války. Písmena tehdy posouvali vždy o 3 znaky v abecedě dopředu. Vytvoříme Caesarovu šifru s posunutím +4. Na vstupu (případně v souboru jako argumentu) bude program získávat otevřený text a následně vypisovat text šifrovaný. K tomu potřebujeme cyklicky získávat řádky textu a zpracovávat je pomocí konstrukce tr. Posunutí +4 znamená, že a nahrazujeme za e, b za f, ..., v za z, w za a, x za b, y za c a z za d. Takhle bude vypadat šifrovaná abeceda:
Otevřenou abecedu nahradíme šifrovanou:
tr/abcdefghijklmnopqrstuvwxyz/efghijklmnopqrstuvwxyzabcd/; Můžeme také využít rozsahy:
tr/a-z/e-za-d/; Vytvoříme cyklus, každou iteraci se načte řádek textu, provede se zašifrování a vytiskne se šifrovaný text:
while ($radek = <>){ Také u tr lze pomocí výchozí proměnné vynechat operátor =~.
while (<>){ A abychom dovedli tuto ukázku téměř k dokonalosti, budeme nahrazovat i velká písmena:
while (<>){ PřepínačePro tr existují dohromady 3 přepínače. V tabulce je jejich přehled.
Přepínač s
$text = "xxxxyxx"; Podřetězce 'xxxx' a 'xx', jsou každý nahrazeny pouze jedním znakem X. Je tak vytisknuto 'XyX'. Přepínač c
$text = "xxxxyxXXxx"; Bez uvedení přepínače by byla nahrazena všechna velká písmena mezerou. Protože zde ale je c, nahrazuje se vše mimo velkých písmen a tiskne se ' XX '. V případné kombinaci s přepínačem s by výsledkem byl řetězec ' XX ' Přepínač d
$text = "ABCDEFGH"; Vytisknuto je jen 'xDEFGH'. Hledáme znaky ABC, z nich pro B a C nemáme náhradu, a protože je uveden přepínač d, budeme je nahrazovat prázdným řetězcem. V případě, že by zde přepínač d nebyl, B a C by se nahrazovaly stejně jako A znakem x. Počet výskytů znaku v řetězciProtože výraz s operátorem =~ vrací počet nahrazení, vrací zároveň počet původních i nových znaků. Pokud tedy nahrazujeme znak stejným znakem, žádné změny v řetězci nenastanou. Pouze získáme počet výskytů. Řádek kódu přiřazuje do proměnné $vyskytu počet výskytů znaku x v obsahu proměnné $text:
$vyskytu = $text =~ tr/x/x/;
Příště budeme pokračovat přepínači a speciálními konstrukcemi v perlových regulárních výrazech.
|
Search Software
Search Google
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
©Pavel Kysilka - 2003-2024 | maillinuxsoft.cz | Design: www.megadesign.cz |