Usuń n linii, pomiń skrypt 1-liniowy

10

Chcę stworzyć podstawowy skrypt Vima, który po prostu usuwa n wierszy, pomija 1 wiersz i powtarza do końca dokumentu. Nie dbam o konkretne dopasowania, chcę po prostu usunąć linię. Na przykład; Chcę więc powtórzyć polecenie 3ddjdla całego dokumentu.

Text I want to keep.   
Text I want to delete.  
Text I want to delete.  
Text I want to delete.  
Text I want to keep.  
Text I want to delete.  
Text I want to delete.  
Text I want to delete.  
Text I want to keep.  
Text I want to delete.  
Text I want to delete.  
Text I want to delete.   

Wygląda to na ...

Text I want to keep.  
Text I want to keep.  
Text I want to keep.  

Dziękuję Ci.

Max Copley
źródło
Umieściłeś tag regular-expressionw swoim pytaniu, ale wydaje się, że pytanie nie określa powodu, dla którego należy to zrobić za pomocą wyrażeń regularnych. Jeśli faktycznie szukasz czegoś, co korzysta z wyrażeń regularnych, to stackoverflow.com/questions/17735289/... może być interesujące. To pytanie dotyczyło Notepad ++, ale w odpowiedzi użyto tylko wyrażenia regularnego pcre. (Zastrzeżenie: Napisałem tę odpowiedź.)
Jasper,
Następnym razem, gdy zadasz pytanie, nie musisz pisać „Dzięki za to. Świetne rozwiązanie!” na każdą odpowiedź. Jest to nawet zapisane, gdy próbujesz utworzyć nowy komentarz do odpowiedzi.
rura
Aby dodać do tego, właściwym sposobem okazania uznania jest zaakceptowanie odpowiedzi, która była dla Ciebie najlepsza i głosowanie za odpowiedziami, które uważasz za pomocne lub przydatne. Ludzie woleliby to zobaczyć niż komentarz „dzięki”.
B Layer

Odpowiedzi:

19

Bardzo proste podejście:

  1. Przejdź do pierwszego wiersza, który chcesz usunąć.
  2. Nagraj makro: qa3ddjq
  3. Powtórz to z wysoką liczbą: 1000 @ a

Krok trzeci powtórzy makro tysiąc razy lub do momentu wystąpienia błędu. Wciśnięcie końca pliku (stąd brak wierszy do usunięcia) powoduje błąd, a powtórzenie makra jest anulowane.

Zobaczyć :help recording.

Ralf
źródło
2
To jest wspaniałe!!! Dziękuję bardzo, że mi to zadziałało: D
Max Copley,
1
objaśnienia: q(w trybie komend, w vimie lub innych najnowszych wersjach alternatywnych [neovim itp.], ale nie w oryginalnym vi) oznacza „rozpocznij nagrywanie i umieść go w buforze„ następnej litery ”. stąd: qaoznacza „rozpocznij nagrywanie w buforze„ a ”. Następnie wszystkie klawisze wpisane po tym (do następnego qw trybie poleceń) są zapisywane (możesz nawet nagrywać: przejście do trybu edycji, wpisanie czegoś, przejście do trybu poleceń itp.). Następnie 12@apowtórzyłby wszystkie działania zapisane w buforze „a” 12 razy.
Olivier Dulac
3
Dodatkowo, jeśli nie chcesz uruchamiać czegoś takiego jak 1000@qna końcu, możesz utworzyć makro rekurencyjne: qa3ddj@aq@achociaż może zajść potrzeba, qaqaby upewnić się, że "azaczyna się od pustego.
James
17

Najłatwiejszym rozwiązaniem byłoby dla mnie:

:%norm j3dd

To jest:

  • %: dla każdej linii
  • norm: uruchom następujące klawisze, jak w trybie normalnym
  • j3dd: zejdź na dół, a następnie usuń 3 linie

Więc od pierwszego wiersza zejdź do drugiego i usuń kolejne 3 wiersze. Drugi Text I want to keep.jest teraz na drugiej linii. Przejdź w dół o jedną linię, usuń 3. Opłucz i powtórz.


Uwaga: jeśli nie chcesz przetwarzać całego pliku, możesz go zastąpić %normnp. 5,$normAby przetworzyć od 5. linii do końca pliku.

Marth
źródło
4
Bardzo fajna alternatywa! Działa w vimie (nie vi). Nigdy wcześniej nie słyszałem o „normie”! (i jestem trochę maniakiem vi [m])
Olivier Dulac
6

Masz już kilka świetnych rozwiązań. Oto kolejny:

:g/^/if line('.')%4!=1|:s/^/DELETE ME/|endif
:g/^DELETE ME/d

Najpierw wykonujemy akcję na każdej linii ( :gdopasowując do ^(początku linii)) i dla każdego numeru linii wykonujemy wynik linenumber % 4. Jeśli wynik jest nierówny 1, dodajemy DELETE MEna początku linii, zaznaczając linie do usunięcia za pomocą następnego polecenia.

Następne polecenie to polecenie regularne ( :g), które pasuje do wszystkich linii, które zaczynają się od niego, DELETE MEi robi to.

Uwaga: Nie można natychmiast usunąć linii za pomocą pierwszego :gpolecenia, ponieważ zmieniłoby to wynikowe obliczenia modulo i jako takie musimy najpierw zaznaczyć linie, a w drugim etapie usunąć je.

Christian Brabandt
źródło
4

Wiem, że to jest vikanał, ale dla mnie to sedproblem.

sed -ne 'p;n;n;n' <file >newfile

Możesz więc wdrożyć go do virozwiązania:

:0
!Gsed -ne 'p;n;n;n'
dgc
źródło
1
+1 za rozwiązanie sed.
Christian Brabandt,
3

Alternatywa (przypuszczam, że zaczynamy od linii 1 i usuwamy linie 2-4, 6-8 itd., Jak w przykładowym tekście):

while line(".") < line("$")
    silent +1delete _ 3
endwhile

Jeśli wolisz robić to interaktywnie, możesz skorzystać z „rejestru wiersza poleceń”. To znaczy naciśnij

:+1del 3<CR> i wtedy 1000@:

Matt
źródło
1

alternatywa: chcesz zachować dowolne wiersze: 1, 4 itd. Możesz użyć:

awk '!((FNR-1)%3)'  file > newfile
      # awk: when a condition is given without action:
      #        prints the lines for which the condition returns 0.
      # FNR designates the line number in the current file.
      # a%3 : takes the modulus of a and 3. ( 0%3=0, 1%3=1, 2%3=2, 3%3=0, 4%3=1, etc.) 
      # This will be 0 for 3, 6, etc. 
      # But we want it to be 0 (true) for 1, 4, etc : so we substract 1 to NR

# to see that it keeps those lines:
seq 1 20 | awk '!((NR-1)%3)'
1
4
7
10
13
16
19

inna alternatywa: jeśli znasz linie, które chcesz dopasować do jakiegoś unikalnego wzoru:

# for exemple each line you want contains "some pattern":
fgrep "some pattern" file > newfile
# (or regular grep if you want "some pattern" to be interpreted as a regexp)
Olivier Dulac
źródło