Ho un file di testo come questo (utilizzando gVim su Windows)
foo bar baz quux corge grault garply waldo fred plugh [...150 more lines...] xyzzy thud
Voglio aggiungere un numero a ogni riga del file. Non utilizzando :set number
, ma per aggiungere il numero come testo che precede ogni riga, come segue, in modo che il numero faccia parte del file.
1. foo bar baz quux 2. corge grault garply 3. waldo fred plugh [...~150 more lines...] 155. xyzzy thud
Commenti
Rispondi
In puro stile Vim:
:%s/^/\=line(".").". "
Spiegazione:
:%s/^/ " the substitution will be applied to the beginning of every line \= " the rest of the replacement part is an expression line(".").". " " the expression returns the current line number concatenated with a dot and a space
Vedi :help \=
e :help line()
.
Usare unespressione nella parte di sostituzione è molto potente e FWIW è un ottimo punto di ingresso per vimscript.
Commenti
- Come posso aggiungere questo comando molto utile a una mappa di tasti in vimrc?
- Per accedere allargomento della guida di vim per la sostituzione:
:help sub-replace-expression
Risposta
Una cosa bella delle macro Vim è che possono ricorrere (possono invocare se stesse ):
- Cancella registro q:
qqq
- Aggiungi il numero alla prima riga:
ggI1.
(non dimenticare lo spazio!) - Torna allinizio della riga e inizia a registrare una macro:
0qq
- Copia il numero:
- Spostati in basso di una riga e incolla il numero:
+P
- Torna allinizio della riga e incrementa il numero:
0<c-a>
- Torna allinizio della riga (così la macro non si interrompe quando arriva a due cifre!):
0
- Chiama la macro una volta, per renderla ricorsiva. A questo punto, non cè ancora nulla nel registro q, quindi non accadrà nulla:
@q
. - Salva la macro:
q
- Richiama la macro ancora una volta e guarda le scintille volare !:
@@
La macro quindi continua a invocare se stesso fino a raggiungere la fine del file.
Puoi usare il trucco della macro ricorsiva per molti altri problemi simili, quindi è “bene esserne consapevoli.
Se per qualche motivo non desideri utilizzare una macro ricorsiva, puoi omettere i passaggi 1 e 8 e utilizzare un conteggio per eseguire la macro più volte, ad es. 100@q
eseguirà la macro q
100 volte.
Commenti
- Roba potente, mi inchino alla tua maestria. Le macro sono come la magia nera per me …
- @ropata, una macro è solo una sequenza di comandi in modalità (per lo più) normale.
- @romainl penso che sia ‘ è meglio pensarlo come una sequenza di sequenze di tasti .
- @Rich, può essere una sequenza di molte cose, inclusi i comandi ex.
- @romainl Sì, ‘ è il motivo per cui penso che ‘ sia meglio considerarle come sequenze di tasti. Riproduce esattamente ciò che digiti sulla tastiera (inclusi, come dici, ex comandi), come se avessi digitato tutto manualmente.
Rispondi
Mi piace usare il comando globale di vim per eseguire attività come questa. Ciò si applica allaggiunta di iterazioni allinizio di una riga o alla modifica di un simbolo nel testo. Sembra più complicato delle altre soluzioni, ma è un modello abbastanza flessibile da usare quando lo hai a portata di mano ed è facile da modificare senza pensarci troppo.
Per prima cosa, scegli il tuo intervallo (quali linee desidera applicare questo). Di solito uso segni (ad es.ma
sulla prima riga e mb
sulla seconda, ma puoi anche utilizzare i numeri di riga o la selezione visiva), quindi inserisci una modifica di il seguente comando (attualmente ottimizzato per il tuo caso duso)
:let i=1|"a,"bg/^/s/^/\=i.". "/|let i=i+1
Decostruzione
:let i=1
Questo imposta la variabile i
con un valore iniziale. Di solito gli elenchi iniziano con 1, quindi imposto i a 1.
|
La barra avvia un nuovo comando
"a,"b
Questo imposta lintervallo del comando successivo. Sto andando da mark a
a mark b
, che verrebbe impostato sulla prima e sullultima riga del tuo elenco.
g/^/
Questo è il comando globale. Cerca nel file (o intervallo) una data espressione regolare ed eseguirà il resto della riga di comando su ciascuna delle righe corrispondenti. Sto cercando la corrispondenza di ogni riga cercando “inizio riga”. Se hai un testo come
Item some txt other text Item second item whatever Item third
e vuoi mettere queste etichette solo davanti a Item
e ignora le altre righe, esegui invece g/Item/
o g/^Item/
(assumendo il testo letterale dellarticolo )
s/^/\=i.". "/
Questo esegue lespressione regolare per sostituire linizio della riga con il valore di i
concatenato con a .
. In genere puoi eseguire questa operazione con qualsiasi cosa (ad esempio, sostituisci letichetta Item
con il numero).
|let i=i+1
Anche se la barra avvia un nuovo comando, imposta un secondo comando da eseguire allinterno del comando globale, invece che dopo che il globale è completo. Il risultato è che incrementiamo i
prima che la riga successiva venga elaborata da g. Ecco un altro luogo di flessibilità. La modifica di i può essere qualsiasi cosa (incre ment per 2, chiama una funzione che genera lelemento successivo della sequenza di Fibonacci, qualunque sia).
Rispondi
Aggiungi numeri a tutte le righe
È possibile utilizzare :%!nl -ba
o :%!cat -n
che aggiungeranno numeri di riga a tutte le righe.
Su Windows, “devo avere Cygwin / MSYS / SUA installato.
Aggiungi numeri alle linee selezionate
Per aggiungere numeri solo per le linee selezionate, selezionali in modalità visiva ( v e cursori), quindi al termine – eseguire il comando: :%!nl
(ignora le righe vuote) o :%!cat -n
(righe vuote incluse).
Formattazione
Per rimuovere spazi extra, selezionali nel blocco visivo ( Ctrl + v ) e rimuoverli ( x ).
Per aggiungere alcuni caratteri (.
, :
, ) dopo i numeri, selezionali nel blocco visivo ( Ctrl + v ), quindi aggiungi il carattere ( A , digita il carattere, quindi termina con Esc ).
Commenti
- Questo non fornisce la stessa formattazione data nella domanda. Tuttavia, mi piace la semplicità della soluzione.
- @KarlYngveLerv å g Grazie, incluso nella risposta.
Risposta
Una modifica della romainl “risposta :
:%s/^\(\d\+\. \)\?/\=line(".").". "
Questo non solo aggiungerà numeri di riga, ma sostituirà i numeri di riga in uscita se sono già lì. Ovviamente, se hai inserito una riga a metà, rinumererà tutto come previsto.
Questo funziona sostituendo qualsiasi numero seguito da a. E uno spazio allinizio della riga con un nuovo numero Ovviamente questo si interromperà se hai una riga che inizia già con questo modello, quindi usala con il pensiero.
La parte aggiunta:
-
^
– Inizio della riga -
\(
– Inizia nuovo sottogruppo -
\d\+
– Trova la corrispondenza di una cifra una o più volte -
\.
– Trova la corrispondenza con un punto (
.
) e uno spazio.
-
\)
– Fine sottogruppo -
\?
– Rendi il gruppo opzionale, in modo che funzioni come prima se non cè ancora un numero su questa riga.
Suggerimento bonus :
Per rimuovere i numeri di riga, puoi utilizzare lo stesso modello con la parte repalce vuota:
:%s/^\(\d\+\. \)\?//
Risposta
I1. <esc>^qqyWjP^<C-a>q
Questo numera le prime due righe e puoi premere @q
per numerare le righe successive (o digitare ex. 18@q
se desideri numerare 20 righe in totale).
Spiegazione:
I1. <esc> Number the first line hqq Go back to the start of the line and start recording a macro yWjP Copy the line number to the next line ^<C-a> Increment the next line"s line number q Finish recording
Il vantaggio di questo è che non richiede alcun comando esterno, il che è utile se lavorare con Vim su Windows, ad esempio.
Commenti
- Dopo aver digitato
1. <esc>h
sei sul seconda colonna, non prima colonna. Sostituireih
con0
, dopodiché penso che la tua soluzione dovrebbe essere molto buona. - @KarlYngveLerv å g Spiacenti, è stato un errore di battitura. Grazie, risolto.
- Nessun problema. Tuttavia, non hai ancora aggiornato la spiegazione. Inoltre: su molte tastiere,
^
attende un secondo carattere per consentire combinazioni di digitazione come^a -> â
. Sono ancora daccordo che sia la soluzione migliore, ma penso che anche questo dovrebbe essere menzionato.
Answer
I penso che la risposta scelta sia la migliore, ma nello spirito della varietà, offrirò unalternativa utilizzando un programma esterno:
:%!cat -n
Questo filtrerà tutto il tuo buffer (come indicato da %
) tramite il programma esterno, cat
, dove -n
flag antepone a ogni riga di input un numero di riga.
Questo, ovviamente, richiede che tu abbia cat
installato, il che è vero (probabilmente) per tutti gli Unix -like sistemi.
Dai unocchiata a :help :range!
per maggiori dettagli sul filtraggio attraverso programmi esterni.
Commenti
- Mi rendo conto che il richiedente sta utilizzando gVim su Windows, quindi questa soluzione probabilmente non ‘ funzionerà lì. Tuttavia, penso che offra ancora qualche opportunità per gli altri t o imparare da esso.
- Se ‘ hai installato
msysgit
e lo hai aggiunto al tuo PATH (IIRC it ‘ è unopzione di installazione), questa soluzione dovrebbe funzionare anche su Windows. -
cat -n
non è POSIX, manl
lo è, quindi potrebbe essere un opzione migliore.
Risposta
Una soluzione un po hacker potrebbe essere la seguente (tutto ciò che è scritto tra < e> devono essere inseriti dopo aver premuto Ctrl + v ):
:%normal :redir @"<Enter>:-=<Enter>:redir END<Enter>I<C-R>".<Tab><Esc>kdd
Decostruzione
:%normal {commands}
esegue il comando in modalità normale su ogni riga specificata dallintervallo, in questo caso ogni riga
:redir @"
reindirizza ogni output eseguito dai comandi ex al buffer senza nome.
:.=
è un comando ex che restituisce la riga corrente numero (purtroppo con una nuova riga precedente)
:redir END
interrompe il reindirizzamento al buffer senza nome
I<C-R>".<Tab><Esc>
inserisce il contenuto del buffer senza nome con un file. e una tabulazione allinizio di ogni riga ed esce dalla modalità di inserimento.
kdd
fa una riga in alto e rimuove la nuova riga che è il risultato di:. = comando.
awk
è probabilmente lo strumento per questo lavoro. Ma io ‘ su Windows (sigh).cat
onl
, che possono eseguire righe numeriche, ma non sono ‘ t generalmente disponibile su Windows (come indica OP dal loro commento suawk
). Le prime due soluzioni sono pure Vim. Infine, tutte le linee contro un paragrafo è solo una questione di selezione dellintervallo. Chiaramente non è un grosso problema.