☰ menu
Pavel Satrapa

Nahrazování

Jedním z nejčastěji používaných příkazů editoru ex je nahrazování. Příkaz se nazývá s (substitute) a má následující tvar:

<řádky>s/<co_hledat>/<čím_nahradit>/<volby>

Jako všechny ostatní začíná určením řádků, kterých se má nahrazení týkat. Za příkazem s se uvádějí dva řetězce, jako obvykle vymezené lomítky. První určuje, jaký text má editor hledat, a druhý čím jej nahradit.

Příklad:

Kdybych chtěl v celém textu nahradit řetězec raz řetězcem dva, použil bych:

:%s/raz/dva/

Připomínám, že procento ztělesňuje všechny řádky souboru.

Takto triviální případ vás samozřejmě těžko ohromí, ale především při vyhledávání se ukazuje síla regulárních výrazů. Navíc je můžete používat hned na dvou místech: jednak ve specifikaci řádků (kde se má pravidlo použít), jednak v parametrech vyhledávání. Pokročilejší příklady uvedu později.

Volby

Účinek nahrazování lze ovlivňovat volbami, které se uvádějí za závěrečným lomítkem. Nejčastěji používané jsou dvě: g a c.

Volba g způsobí, že vim nahradí všechny výskyty řetězce na řádku. Implicitně totiž nahrazuje pouze první z nich, takže z řádku

raz raz raz dvá raz

(oblíbené vojenské zaklínadlo pro synchronizaci pochodujících) by příkaz

:s/raz/dva/

udělal

dva raz raz dvá raz

Teprve příkaz

:s/raz/dva/g

zajistí nahrazení všech slov a vznikne

dva dva dva dvá dva

Abych mluvil skutečnou pravdu, chování vim závisí na nastavení parametru gdefault. Pokud je zapnut (:set gdefault), editor implicitně nahrazuje všechny výskyty řetězce na řádku. Při použití volby g pak bude nahrazovat vždy jen první kousek na každém řádku. Vypnutý parametr (:set nogdefault) pak zajistí výše popsané chování, které je implicitní pro původní editor vi i řadu dalších programů systému Unix.

Volba c umožňuje potvrzování každé náhrady. Zadáte-li

:%s/raz/dva/gc

vim se pokusí nahradit všechny řetězce raz v textu, ale každý z nich nejprve předvede a dotáže se, zda jej má skutečně nahradit. Tato vlastnost je velmi užitečná, pokud se necítíte silní v kolenou a máte jisté obavy, že hledanému řetězci by mohlo vyhovět i něco navíc proti vašemu záměru. Svou odpověď můžete vybírat z obvyklých možností:

y nahradit daný výskyt
n ponechat tento výskyt v původním tvaru a pokračovat dál
[Esc] nebo q ponechat tento výskyt v původním tvaru a ukončit nahrazování
a nahradit tento a všechny následující výskyty

Komplikovanější příklady

Kdysi jsem v jednom zdrojovém textu potřeboval všechny číselné údaje vydělit deseti. To vlastně znamená vyhledat všechna čísla a před poslední číslici do nich vložit tečku. Zmíněnou akci obstará příkaz

:%s/\([0-9]*\)\([0-9]\)/\1.\2/g

Hledá skupiny číslic a ty si díky mechanismu zapamatování (kulaté závorky s lomítkem) rozdělí vždy na dvě části. První je dlouhá podle potřeby a druhá obsahuje vždy právě jednu (poslední) číslici. V nahrazovacím řetězci jen zopakuje tyto zapamatované skupiny, avšak mezi ně vloží tečku.

Nedávno jsme měnili strukturu domácích adresářů uživatelů na disku. Pro každého uživatele obsahoval soubor informace o uživatelském jméně a domácím adresáři – například

PAVEL.SATRAPA,USR:HOME\KIT\SATRAPA

Soubor byl uspořádán abecedně podle uživatelských jmen. My jsme však potřebovali seskupit uživatele podle kateder, které se projevují v cestě k domácímu adresáři za adresářem HOME (jakožto příslušník katedry informačních technologií bydlím v adresáři KIT). Potřebovali jsme tudíž vycucnout dotyčné jméno adresáře a zapsat je jako první údaj na řádku - abychom obdrželi

KIT,PAVEL.SATRAPA,USR:HOME\KIT\SATRAPA

Takový soubor pak stačí protáhnout standardním programem sort a členové jednotlivých kateder se rázem ocitnou pospolu. Potřebnou transformaci obstará

:%s/^\(.*:HOME\\\)\([^\\]*\)/\2,\1\2

Při vyhledávání si příkaz zapamatuje vše od začátku řádku až po řetězec :HOME\ (jelikož lomítko má speciální význam, musí se v hledaném řetězci zdvojit). Pod číslem 2 se následně zapamatuje řetězec znaků, odlišných od lomítka (jinými slovy celý název adresáře až po následující lomítko). V nahrazovacím řetězci se nejprve vypíše tento název adresáře, za ním čárka a pak beze změny obě zapamatované části textu. Zbytek řádku zůstane zachován (hledaný regulární výraz se na něj nevztahuje).