Vim: jak usunąć co drugi wiersz?

99

Jak to zrobić w Vimie:

PRZED:

aaa
bbb
ccc
ddd
eee
fff

PO:

aaa
ccc
eee
brazh
źródło
Powinieneś móc użyć makra: oreillynet.com/mac/blog/2006/07/ ...
Mark Wilkins,
Podoba mi się bogactwo odpowiedzi na to pytanie. Ulubione.
froggythefrog

Odpowiedzi:

105

Możesz do tego użyć makra. Wykonaj następujące czynności.

  • Uruchom w trybie poleceń.
  • Przejdź na początek pliku, naciskając gg.
  • Naciśnij qq.
  • Kliknij strzałkę w dół i naciśnij ddpo.
  • Naciśnij q.
  • naciśnij 10000@q

PS: Aby przejść do trybu poleceń, po prostu naciśnij klawisz Escape kilka razy.

rui
źródło
11
Zakładając, że twój plik ma oczywiście mniej niż 20000 linii :-)
paxdiablo
3
Właściwie mylisz się Michael. Działa to bezbłędnie, ponieważ VI przestanie uruchamiać makro, gdy tylko osiągnie koniec pliku. Możesz to bardzo łatwo wypróbować z powyższą próbką.
rui
1
Cóż, jak każde makro, które musisz zrobić dobrze za pierwszym razem, ale potem możesz zastosować do dowolnego pliku, wpisując po prostu 10000 @ q. Tak czy inaczej uważam, że to tylko kwestia gustów, więc definitywnie nie mam zamiaru rozpoczynać filozoficznej debaty. :)
rui
3
Wolę używać „makro”. Używając makra, „opisujesz”, w jaki sposób rozwiązałbyś jedno konkretne zadanie i pozwalasz VIMowi je powtórzyć. RUI, wolałbym użyć „j” zamiast klawisza strzałki.
Rozwiązanie
4
:g/^/+dz user stackoverflow.com/users/254635/ib (poniżej) to bardziej elegancki sposób rozwiązania tego problemu.
SergioAraujo
256

Eleganckim (i wydajnym) sposobem wykonania zadania jest wywołanie :+deletepolecenia usuwającego wiersz następujący po bieżącym, w każdym wierszu za pomocą :globalpolecenia:

:g/^/+d
ib.
źródło
10
Dlaczego ta odpowiedź nie otrzymała więcej głosów pozytywnych? To jest takie czyste i proste. Alternatywnie możesz usunąć pierwszą linię i uruchomić powyższe polecenie, aby usunąć wszystkie nieparzyste linie.
Usagi
3
@Usagi: Dziękuję! Czuję co do tego to samo. I tak, masz absolutną rację, :1d|g/^/+dusuwa nieparzyste linie.
ib.
@Usagi Druga odpowiedź została wybrana jako „najlepsza odpowiedź” 2 lata przed pojawieniem się jego odpowiedzi. Ponadto, chociaż jest to bardziej eleganckie rozwiązanie, mogłoby zostać napisane w bardziej użyteczny sposób (tj. Nie ma wzmianki o tym, co robi ^, podczas gdy makro jest łatwe do zrozumienia dla każdego).
user1271772
3
Przepraszam, ale bez wyjaśnienia, w jaki sposób to polecenie wykonuje pożądane zachowanie, nie głosowałbym go za nim, a zamiast tego wolałbym zaakceptowaną odpowiedź, ponieważ rozumiem, w jaki sposób osiąga cel. To różnica między daniem człowiekowi ryby a nauczeniem go łowienia.
Gabe
3
Nie wiem, ta odpowiedź sprawiła, że ​​wyszedłem i nauczyłem się łowić za pomocą polecenia: g (to znaczy, że wygooglowałem tę stronę - vim.wikia.com/wiki/Power_of_g ).
snetch
67

Możemy użyć :normallub :normdo wykonania podanych poleceń trybu normalnego. Źródło.

:%norm jdd
Tadhg
źródło
15
Ta odpowiedź nie przyciąga wystarczającej uwagi, być może z powodu braku wyjaśnienia zarówno tutaj, jak i na połączonym, niechlujnym, ściągawce. polecenie norm uruchamia polecenia trybu normalnego odpowiadające następującym po nim literom. Więc tutaj działa j, aby przejść w dół o linię i dd, aby ją usunąć. Można to uogólnić w linii X, dodając więcej „j” w tym przypadku.
imoatama
5
a% to skrót od 1, $ (wykonaj następujące polecenie od wiersza 1 do końca)
Lambart
3
Interesuje mnie, dlaczego %norm ddjnie działa, jeśli chcesz usunąć nieparzyste wiersze.
Cyker,
10
:map ^o ddj^o
^o

Tutaj ^ oznacza CTRL. Makro rekurencyjne do usuwania wiersza co dwa wiersze. Wybierz dobrze swoją pierwszą linię i gotowe.

Raoul Supercopter
źródło
8

z archiwum poczty vim :

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

(Aby wpisać w jednej linii w linii poleceń vim, usunie wiersz 1,3,5,7, ...)

Fortega
źródło
4
Wtedy wolałbym !perl -ne 'print unless $. % 2':-)
Alex Brasetvik
I, Alex, zdecydowanie wolałbym moje rozwiązanie od twojego, ale to warte rozważenia, ponieważ jest to jedyne rozsądne rozwiązanie wykorzystujące tutaj tylko sam vim.
Michael Krelin - haker
Droga makro jest o wiele łatwiejsza.
trusktr
+1 ze względu na elastyczność, z if (expression)jaką działa również dla co trzeciej linii itp.
Jens
5

Zawsze możesz przesłać potokiem przez polecenie powłoki, co oznacza, że ​​możesz użyć dowolnego języka skryptowego:

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

(lub użyj „chyba” zamiast „jeśli”, w zależności od tego, które wiersze chcesz)

szczupły
źródło
Nie potrzebujesz -lprzejścia na Perl ... także, powiedziałbym, że awkjest to trochę bardziej rozpowszechnione niż Perl, chociaż obecnie nie jest to dużo więcej i można to zrobić krócej: :%!awk NR\%2lub :%!awk 1-NR\%2dla innych linii.
ephemient
4
:%!awk -- '++c\%2'

alternatywnie

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

w zależności od tego, którą połowę chcesz wyeliminować.

Michael Krelin - haker
źródło
Umm, dlaczego nie wykorzystać istniejącej NRzmiennej?
ephemient
Dobrze. Bo o tym zapomniałem. ;-) Ale tak naprawdę „właściwy” wariant będzie jeszcze dłuższy z NR. I nie byłoby dwóch ładnie wyglądających odpowiedników.
Michael Krelin - haker
:%!awk NR\%2lub :%!awk 1-NR\%2, jak napisałem w innym komentarzu. To już niewiele dłużej.
ephemient
1
1-NRjest dłuższy niż c++. Tak, wiem, że to jedna postać. Jak powiedziałem - prawdziwy powód jest taki, że o tym zapomniałem. W każdym razie wygląda na to, że ludzie nie doceniają tutaj piękna awk.
Michael Krelin - haker
I NRjest krótszy niż ++c:)
ephemient
3

Możesz użyć własnych możliwości wyszukiwania i zamiany Vima, jak na przykład: Umieść kursor w pierwszej linii i wpisz w normalnym trybie:

:.,/fff/s/\n.*\(\n.*\)/\1/g
  • Jest .,/fff/to zakres dla podstawienia. Oznacza „od tej linii do linii, która pasuje do wyrażenia regularnego fff(w tym przypadku do ostatniej linii).
  • s///jest poleceniem zastępczym. Szuka wyrażenia regularnego i zastępuje każde jego wystąpienie łańcuchem. Na gkońcu oznacza powtórzenie podstawienia tak długo, jak długo znajduje się wyrażenie regularne.
  • Wyrażenie regularne \n.*\(\n.*\)dopasowuje nową linię, następnie całą linię ( .*dopasowuje dowolną liczbę znaków oprócz nowej linii), a następnie kolejną nową linię i kolejną linię. Nawiasy \(i \)powodują zapisanie zawartego w nich wyrażenia, dzięki czemu możemy go później użyć za pomocą \1.
  • \1 wstawia zgrupowany znak nowej linii i wiersz po nim z powrotem, ponieważ nie chcemy, aby następna linia również zniknęła - po prostu chcemy, aby mechanizm podstawiania przeszedł obok niego, więc nie usuwamy go przy następnej zamianie.

W ten sposób możesz kontrolować zakres, w którym ma nastąpić usunięcie, i nie musisz używać żadnego zewnętrznego narzędzia.

Daniel Hershcovich
źródło
Lub $zamiast tego /fff/dla końca pliku, niezależnie od zawartości pliku.
ephemient
3

Jako inne podejście możesz również użyć Pythona, jeśli twój vim ma na to wsparcie.

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

b = cb[:]tymczasowo kopiuje wszystkie linie z bieżącego bufora do b. b[::2]pobiera co drugą linię z bufora i przypisuje ją do całego bieżącego bufora cb[:]. Kopiowanie do bjest konieczne, ponieważ obiekty bufora nie obsługują rozszerzonej składni wycinka.

Prawdopodobnie nie jest to „sposób Vima”, ale może być łatwiejszy do zapamiętania, jeśli znasz Pythona.

qzr
źródło
2

Aby usunąć nieparzyste linie (1, 3, 5, ..) -> :%s/\(.*\)\n\(.*\)\n/\2\r/g

Aby usunąć parzyste linie (2, 4, 6, ..) -> :%s/\(.*\)\n.*\n/\1\r/g

Wyszukaj tekst (tworzy pierwszą linię), po którym następuje znak nowego wiersza i trochę więcej tekstu (tworzy drugą linię), a następnie inny znak nowego wiersza i zamień powyższe na pierwszą zgodność (nieparzysta linia) lub drugą zgodność (parzysta linia) po którym następuje powrót karetki.

kartik kailas
źródło
0

Wywołaj 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
asdmin
źródło
-1

rozwiązanie

możesz spróbować tego w vimie

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

edytować

Spróbuję wyrazić się bardziej jasno (dwie części)

pierwsza część zakres wyboru ( :from,to)
druga część akcja ( dusuń)

  • zakres, jeśli od pierwszej linii do przedostatniej linii ( :1,$-1)
  • globaly ( g) delete ( +1d) następny wiersz

możesz spróbować przejść do pierwszej linii pliku i wykonać :+1d, a następna linia zniknie

Wiem, że jest błotnisty, ale jest vim i działa

wdog
źródło
Czyste jak błoto. Dzięki!
Henry Henrinson