:vim — corso in 10 lezioni
Lezione 06 di 10

Cercare e sostituire

La ricerca in Vim non serve solo a trovare: è un movimento come w o }, quindi si combina con gli operatori. E :s è il comando che, imparato bene, sostituisce mezz'ora di lavoro manuale.

Teoria

Trovare

ComandoEffetto
/testocerca in avanti
?testocerca all'indietro
n   Noccorrenza successiva / precedente, nella stessa direzione
*   #cerca la parola sotto il cursore, avanti / indietro
g*   g#come sopra, ma trova anche le parole che la contengono
/testo/eferma il cursore alla fine della corrispondenza
//ripete l'ultima ricerca senza riscriverla

Trattandosi di un movimento, funziona come argomento di un operatore: d/FINE cancella da qui fino alla prima occorrenza di «FINE», y?inizio copia all'indietro. È il modo più diretto per lavorare su regioni che non hanno un oggetto di testo.

Le quattro opzioni da mettere subito nel .vimrc

OpzioneCosa cambia
:set incsearchevidenzia mentre digiti, prima di premere Invio
:set hlsearchlascia evidenziate tutte le occorrenze
:set ignorecaseignora maiuscole e minuscole
:set smartcase…tranne se scrivi almeno una maiuscola: allora torna sensibile

Le ultime due si usano insieme: errore trova tutto, Errore trova solo la forma con la maiuscola. Per spegnere l'evidenziazione quando dà fastidio: :noh (abbreviazione di :nohlsearch) — non disattiva l'opzione, pulisce solo lo schermo.

Le regex di Vim, in breve

Vim usa una sintassi di espressioni regolari tutta sua, imparentata con le POSIX ma non identica a quelle di grep o Perl. La differenza pratica è che molti metacaratteri vanno preceduti da una barra rovescia:

ScriviSignifica
.   *   ^   $   [ ]come ovunque: carattere qualsiasi, ripetizione, inizio, fine, classe
\+   \?   \{2,5}uno o più · zero o uno · da due a cinque
\| alternativa fra due pattern
\( \)gruppo, richiamabile poi con \1, \2
\<   \>inizio / fine di parola
\d   \w   \scifra · carattere di parola · spazio
\zs   \zesegnano dove la corrispondenza inizia e finisce davvero
Se ti dà fastidio, c'è \v. Messo all'inizio del pattern attiva la modalità very magic, in cui i metacaratteri si scrivono come in Perl o in grep -E: /\v(gatto|cane)+ invece di /\(gatto\|cane\)\+. Su pattern complessi risparmia una selva di barre.
Pratica

Il comando :s pezzo per pezzo

anatomia
:%s/vecchio/nuovo/gc
  │      │       │     │
  │      │       │     └── flag: g = tutte le occorrenze della riga
  │      │       │              c = chiedi conferma ogni volta
  │      │       └──────── sostituto
  │      └──────────────── pattern da cercare
  └─────────────────────── intervallo di righe

Gli intervalli

IntervalloRighe interessate
(niente)solo la riga corrente
%tutto il file
1,50dalla riga 1 alla 50
.,$da qui alla fine
.,+10da qui alle dieci righe successive
'<,'>la selezione visuale — appare da sola se premi : in VISUAL
/inizio/,/fine/dalla riga che contiene «inizio» a quella che contiene «fine»

Esempi che vengono buoni davvero

casi ricorrenti
# cambiare dominio in tutto il file, chiedendo conferma
:%s/vecchiosito\.it/nuovosito\.it/gc

# togliere gli spazi in fondo alle righe
:%s/\s\+$//e

# invertire "Cognome, Nome" in "Nome Cognome" usando i gruppi
:%s/\v(\w+), (\w+)/\2 \1/

# numerare le righe non vuote
:%s/^\(.\+\)$/\=line('.') . '. ' . submatch(1)/

# solo nelle righe che contengono TODO
:%s/priorita: bassa/priorita: alta/g

# incrementare tutti i numeri di versione di uno
:%s/v\zs\d\+/\=submatch(0)+1/g

Nel sostituto valgono \1\9 per i gruppi, & per l'intera corrispondenza, \u e \U per forzare maiuscolo (e \l, \L per minuscolo). Con \= il sostituto diventa un'espressione VimScript, come nei due esempi finali.

Il flag e serve più di quanto sembri. Senza, :s che non trova nulla dà errore — e dentro una macro o un :g l'errore interrompe tutto. Aggiungere e significa «se non c'è, pazienza».
Trucco

Pattern vuoto: cerca prima, sostituisci dopo

Le sostituzioni sbagliate nascono quasi sempre dallo stesso errore: scrivere un pattern complicato dentro :%s/… e premere Invio sperando bene. Il modo prudente è spezzare in due l'operazione — e Vim lo rende naturale, perché se lasci il pattern vuoto riusa l'ultima ricerca.

il flusso in tre passi
/\v<utente_(\d+)>      # 1. costruisci il pattern e guardalo evidenziato
n n n                   # 2. verifica le corrispondenze una a una
:%s//cliente_\1/g        # 3. il pattern vuoto = "quello di prima"

I vantaggi sono tre: il pattern lo hai già visto funzionare con hlsearch; non lo riscrivi, quindi non lo sbagli; e se qualcosa va storto, un u annulla tutta la sostituzione in un colpo solo (è un'unica modifica).

Due comodità che seguono dalla stessa idea

Contare prima di agire. :%s/pattern//gn — con il flag n — non sostituisce nulla e ti dice quante corrispondenze e quante righe ha trovato. È il modo più rapido di rispondere a «quante volte compare questa cosa nel file?».