Vim: come eliminare ogni seconda riga?


Risposte:


105

Puoi usare una macro per questo. Eseguire le seguenti operazioni.

  • Inizia in modalità di comando.
  • Andare all'inizio del file premendo gg.
  • Premere qq.
  • Fare clic sulla freccia verso il basso e premere dddopo.
  • Premere q.
  • stampa 10000@q

PS: per passare alla modalità di comando basta premere Esc un paio di volte.


11
Supponendo che il tuo file sia lungo meno di 20.000 righe, ovviamente :-)
paxdiablo

3
In realtà ti sbagli Michael. Funziona perfettamente poiché VI interromperà l'esecuzione della macro non appena raggiunge la fine del file. Puoi provarlo molto facilmente con l'esempio sopra.
rui

1
Bene, come qualsiasi macro è necessario eseguire correttamente la prima volta, ma dopo è possibile applicare a qualsiasi file semplicemente digitando 10000 @ q. In ogni caso credo che sia solo una questione di gusti, quindi non avvierò definitivamente un dibattito filosofico. :)
rui

3
Preferisco usare "macro". Usando la macro, 'descrivi' come risolveresti un compito particolare e lascia che VIM lo ripeta per te. RUI, preferirei usare "j" invece del tasto freccia.
SoluzioneYogi

4
:g/^/+ddall'utente stackoverflow.com/users/254635/ib (sotto) è un modo più elegante per risolvere questo problema.
SergioAraujo

254

Un modo elegante (ed efficiente) per eseguire l'attività è invocare il :+deletecomando rimuovendo la riga successiva a quella corrente, su ogni riga utilizzando il :globalcomando:

:g/^/+d

10
Perché questa risposta non ha ottenuto più voti positivi? Questo è così semplice e pulito. In alternativa è possibile eliminare la prima riga ed eseguire il comando precedente per eliminare tutte le righe dispari.
Usagi

3
@Usagi: grazie! Mi sento allo stesso modo al riguardo. E sì, hai perfettamente ragione, :1d|g/^/+dcancella le righe dispari.
ib.

@Usagi L'altra risposta è stata selezionata come "migliore risposta" 2 anni prima che la sua risposta apparisse. Inoltre, sebbene questa sia una soluzione più elegante, avrebbe potuto essere scritta in un modo più utile (cioè non si fa menzione di cosa fa ^, mentre la macro è facile da capire per chiunque).
user1271772

3
Scusa, ma senza una spiegazione di come quel comando esegue il comportamento desiderato, non lo voterei a favore e preferirei invece la risposta accettata, poiché capisco come realizza l'obiettivo. È la differenza tra dare un pesce a un uomo e insegnargli a pescare.
Gabe

3
Non lo so, questa risposta mi ha fatto uscire e imparare a pescare con il comando: g (cioè mi ha fatto google questa pagina - vim.wikia.com/wiki/Power_of_g ).
snetch

67

Possiamo usare :normalo :normper eseguire dati comandi in modalità normale. Fonte.

:%norm jdd

15
Questa risposta non ottiene abbastanza attenzione, forse a causa della mancanza di spiegazioni sia qui che sul foglio collegato, disordinato, cheat. il comando norm esegue i comandi in modalità normale equivalenti alle lettere che lo seguono. Quindi qui è in esecuzione j per spostarsi verso il basso di una riga e dd per eliminarlo. Questo è generalizzabile alla riga X aggiungendo più j in questo caso.
imoatama

5
e% è una scorciatoia per 1, $ (esegui il seguente comando dalla riga 1 alla fine)
Lambart

3
Mi interessa il motivo per cui %norm ddjnon funziona se vuoi eliminare le righe dispari.
Cyker

10
:map ^o ddj^o
^o

Qui ^ sta per CTRL. Macro ricorsiva per eliminare una riga ogni due righe. Scegli bene la tua prima riga e il gioco è fatto.


8

dall'archivio di posta di vim :

:let i=1 | while i <= line('$') | if (i % 2) | exe i . "delete" | endif | let i += 1 | endwhile

(Per essere digitato su una riga nella riga di comando di vim, cancellerà la riga 1,3,5,7, ...)


4
Allora preferirei !perl -ne 'print unless $. % 2':-)
Alex Brasetvik

E, Alex, preferirei sicuramente la mia soluzione alla tua, ma vale la pena prenderla in considerazione poiché questa è l'unica soluzione sensata che utilizza solo vim stesso qui.
Michael Krelin - hacker

Il modo macro è molto più semplice.
trusktr

+1 per la flessibilità con if (expression)cui funziona anche per ogni terza linea ecc.
Jens

5

Puoi sempre eseguire il pipe tramite un comando shell, il che significa che puoi utilizzare qualsiasi linguaggio di scripting che ti piace:

:%!perl -nle 'print if $. % 2'

(o usa "a meno che" invece di "se", a seconda delle linee che vuoi)


Non è necessario il -lpassaggio a Perl ... inoltre, direi che awkè un po 'più diffuso di Perl, anche se non è molto di più in questi giorni, e può farlo più breve:, :%!awk NR\%2o :%!awk 1-NR\%2per le altre righe.
effimero

4
:%!awk -- '++c\%2'

in alternativa

:%!awk -- 'c++\%2'

a seconda di quale metà vuoi estirpare.


Umm, perché non utilizzare la NRvariabile esistente ?
effimero

Destra. Perché me ne sono dimenticato. ;-) Ma in realtà, la variante "corretta" sarà ancora più lunga con NR. E non ci sarebbero due controparti di bell'aspetto .
Michael Krelin - hacker

:%!awk NR\%2oppure :%!awk 1-NR\%2, come ho postato in un altro commento. Non è quasi più lungo.
effimero

1
1-NRè più lungo di c++. Sì, lo so che è un personaggio. Come ho detto, il vero motivo è che me ne sono dimenticato. Ad ogni modo, sembra che le persone non apprezzino la bellezza di awk qui.
Michael Krelin - hacker

Ed NRè più breve di ++c:)
effimero

3

Puoi usare le capacità di ricerca e sostituzione di Vim in questo modo: Posiziona il cursore sulla prima riga e digita in modalità normale:

:.,/fff/s/\n.*\(\n.*\)/\1/g
  • Il .,/fff/è l'intervallo per la sostituzione. Significa "da questa riga alla riga che corrisponde alla regex fff(in questo caso, l'ultima riga).
  • s///è il comando sostitutivo. Cerca una regex e ne sostituisce ogni occorrenza con una stringa. Alla gfine significa ripetere la sostituzione finché la regex continua a essere trovata.
  • L'espressione regolare \n.*\(\n.*\)corrisponde a una nuova riga, quindi a un'intera riga ( .*corrisponde a un numero qualsiasi di caratteri eccetto una nuova riga), quindi un'altra nuova riga e un'altra riga. Le parentesi \(e fanno \)sì che l'espressione al loro interno venga registrata, quindi possiamo usarla in seguito usando \1.
  • \1 inserisce la nuova riga raggruppata e la riga dopo di essa, perché non vogliamo che anche la riga successiva vada via - vogliamo solo che il meccanismo di sostituzione passi oltre in modo da non eliminarla nella sostituzione successiva.

In questo modo puoi controllare l'intervallo in cui desideri che venga eseguita l'eliminazione e non devi utilizzare alcuno strumento esterno.


O $invece di /fff/, per la fine del file indipendentemente dal contenuto del file.
effimero

3

Come altro approccio potresti anche usare python se il tuo vim ha il supporto per esso.

:py import vim; cb = vim.current.buffer; b = cb[:]; cb[:] = b[::2]

b = cb[:]copia temporaneamente tutte le righe nel buffer corrente in b. b[::2]ottiene ogni seconda riga dal buffer e la assegna all'intero buffer corrente cb[:]. La copia in bè necessaria poiché gli oggetti buffer non sembrano supportare la sintassi della sezione estesa.

Questo probabilmente non è il "modo vim", ma potrebbe essere più facile da ricordare se conosci python.


2

Per eliminare le righe dispari (1,3,5, ..) -> :%s/\(.*\)\n\(.*\)\n/\2\r/g

Per eliminare le righe pari (2,4,6, ..) -> :%s/\(.*\)\n.*\n/\1\r/g

Cerca testo (forma la prima riga) seguito da un nuovo carattere di riga e altro testo (forma la seconda riga) seguito da un altro nuovo carattere di riga e sostituisci quanto sopra con la prima corrispondenza (riga dispari) o la seconda corrispondenza (riga pari) seguito da ritorno a capo.


0

Invoca sed:

:% !sed -e '2~2 d'

^^^^                  pipe file through a shell command
    ^^^^^^            the command is sed, and -e describes an expression as parameter
            ^^^^^     starting with the second line, delete every second line

-1

soluzione

puoi provarlo in vim

:1,$-1g/^/+1d

modificare

Cercherò di essere più chiaro (due parti)

prima parte l'intervallo di selezione ( :from,to)
seconda parte l'azione ( delimina)

  • l'intervallo se dalla prima riga all'ultima riga (:1,$-1 )
  • globaly ( g) delete ( +1d) riga successiva

puoi provare a spostarti sulla prima riga del tuo file ed eseguirlo :+1dvedrai scomparire la riga successiva

So che è fangoso, ma è vivo e funziona


Chiaro come il fango. Grazie!
Henry Henrinson
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.