Jak odwrócić co 4 linie?

13

Po pierwsze, ponieważ jest to mój pierwszy post tutaj, chciałbym tylko powiedzieć, że VIM jest świetnym narzędziem, a forum tutaj bardzo pomocne w znajdowaniu odpowiedzi na pytania, z dużą ilością pomocnych osób nieoceniona pomoc. Nadal jestem bardzo nowy w VIM, więc prawie wszystko, czego się o nim dowiedziałem, pochodzi.

Moje pytanie brzmi: wiem, jak odwrócić WSZYSTKIE linie w pliku (między innymi: g / ^ / m0), ale czy istnieje sposób na odwrócenie co 4 linie w pliku, tak aby

line1
line2
line3
line4
line5
line6
line7
line8
...

staje się

line4
line3
line2
line1
line8
line7
line6
line5
...

Możesz założyć, że w takich plikach zawsze będzie dokładna wielokrotność 4 linii.

blewasiereisawelba
źródło
2
O twoim „ps”: jeśli wstawisz 4 spacje przed linią, jest to interpretowane jako kod (możesz zaznaczyć tekst i użyć przycisków formatowania u góry). Więcej informacji można znaleźć na górze ikony przesłuchania .
mMontu

Odpowiedzi:

15

Można do tego użyć komendy :Reverseobjaśnionej na Vim Wiki (możesz włączyć ją do swojej, .vimrcaby była stała):

command! -bar -range=% Reverse <line1>,<line2>g/^/m<line1>-1|nohl

Następnie możesz nagrać makro, aby uruchomić polecenie co cztery linie:

qmV3j:Reverse<cr>4jq
1000@m

Wyjaśnienie:

  • qm: „q” w trybie normalnym rozpoczyna (i zatrzymuje) rejestrowanie makra w danym rejestrze (w tym przypadku zarejestruj „m”, ale może to być dowolna inna litera)
  • V: wejdź w tryb wizualny i wybierz bieżącą linię
  • 3j: rozwiń zaznaczenie wizualne do następnych 3 linii
  • :Reverse<cr>: uruchom polecenie Odwróć w wybranych liniach ( <cr>tutaj oznacza enterklawisz)
  • 4j: przejdź do następnych niezmienionych linii
  • q: zatrzymuje rejestrowanie makra
  • 1000@m: uruchom makro zarejestrowane w rejestrze „m” 1000 razy (możesz zwiększyć tę liczbę, jeśli plik ma więcej niż 4000 linii)

Edytować:

Jak wspomniano w komentarzach, możesz użyć makra rekurencyjnego zamiast liczenia:

qmV3j:Reverse<cr>4jq
qM@mq
@m
  • qM: jeśli rejestr podany jako qwielka litera, makro jest dołączane do rejestru (jest to również przydatne, gdy zauważysz, że przegapiłeś ostatnie kroki na złożonym makrze)
  • @m: uruchom makro przy rejestracji m
  • q: przestań dodawać makro

Pomimo tego, że jest tworzony jako makro, możesz utworzyć dla niego komendę, jeśli jest to typowe zadanie w twoim przepływie pracy:

function! Reverse4()
   let reg_m = @m
   let @m = '<c-r><c-r>m'
   normal! @m
   let @m = reg_m
endfunction
command! Reverse4 call Reverse4()
  • function! Reverse4()/ endfunction: definiuje nową funkcję
  • let reg_m = @m: zapisuje bieżącą zawartość rejestru m
  • let @m = "<c-r><c-r>m": wstaw makro do rejestru m- zwróć uwagę, że <c-r>jest to notacja vim dla Ctrl+ ri że powinieneś to wpisać , a nie kopiować / wklejać, więc twoja linia będzie podobna let @m = 'V3j:Reverse^M4j@m'i będzie zawierała znak specjalny (^ M)
  • normal! @m: normalne polecenie uruchamia swój argument, ponieważ zostało wpisane w trybie normalnym, więc uruchomi makro rekurencyjne
  • let @m = reg_m: przywraca zawartość rejestru m, więc nie musisz pamiętać, że ten rejestr jest używany w tej funkcji i unikaj jego używania

  • command! Reverse4 call Reverse4(): utwórz nowe polecenie dla tej funkcji

W zależności od potrzeb możesz go ulepszyć, np .: przekazać argument do polecenia i funkcji, aby działał dla dowolnej liczby linii zamiast być ustalony w grupach po 4 linie.

mMontu
źródło
Zamiast 1000@qsiekać, można również użyć makra rekurencyjnego: qmqqm ... @mq@m.
Klamka
Kiedy próbowałem uruchomić „qmV3j: Reverse <cr> 4jq”, powiedział „E492: Nie polecenie edytora”. Muszę robić coś złego. Nawiasem mówiąc, używam GVIM - i tylko go używałem. Powinienem przede wszystkim o tym wspomnieć.
ablewasiereisawelba
Ah nie ważne. Zrozumiałem - nie powinienem pisać „:” przed częścią „qmV3j: Reverse <cr> 4jq”. Zadziałało! Dziękuję bardzo, mMontu. Jeśli mogę zapytać - jak dołączyć polecenie „: Reverse” do mojego pliku .vimrc?
ablewasiereisawelba
3
@ablewasiereisawelba Aby komenda była dostępna na stałe, po prostu napisz wiersz command! -bar -range=% Reverse <line1>,<line2>g/^/m<line1>-1|nohlgdzieś w vimrc.
saginaw
@saginaw Oh, nie zdawałem sobie sprawy, że to było takie proste. Dziękuję Ci.
ablewasiereisawelba
9

Podobnie jak w przypadku wszystkich powtarzających się czynności , jeśli możesz zrobić coś raz za pomocą podstawowych operacji edycji, możesz to zrobić wiele razy, rejestrując makro.

(W tym przypadku użyję makra rekurencyjnego, ale możesz po prostu nagrać makro nierekurencyjne i odtworzyć je wiele razy młotkiem @@lub za pomocą liczenia).

ggqqqqqddjjpkddkkPjddpjj@qq@q

Zepsuty

  1. gg: Przejdź na początek pliku.
  2. qqq: Wyczyść rejestr q. Zobaczymy, dlaczego jest to konieczne w kroku 5.
  3. qq: Rozpocznij rejestrowanie makra, aby zarejestrować q
  4. ddjjpkddkkPjddpjj: Seria operacji, która zmienia kolejność pierwszych czterech wierszy po prostu usuwając je i wklejając ręcznie. (To może wyglądać na pierwszy rzut oka skomplikowane, ale nie daj się zwieść Jest to bardzo podstawowe rzeczy, które chcesz nauczyliśmy w ciągu pierwszych 5 minut albo tak. vimtutor: j, k, dd, p, P)
  5. @q: Wywołaj makro! W tym momencie rejestr qnie zawiera niczego (ponieważ wyczyściliśmy go w kroku 2), więc nic się nie stanie.
  6. q: Zatrzymaj rejestrowanie makra.
  7. @q: Odtwórz makro rekurencyjne tyle razy, ile to konieczne.

Uwaga: Powyższe nie przyniesie pożądanych rezultatów, jeśli plik zawiera szereg linii, których nie da się dokładnie podzielić przez cztery. Aby zatrzymać makro wcześnie, jeśli nie pozostały już cztery wiersze, musimy wykonać polecenie trybu normalnego Vima, które zakończy się niepowodzeniem, zanim zaczniemy wprowadzać zmiany w kroku 4. Możemy to zrobić, próbując przejść w dół linię trzy razy (a następnie cofnij), zanim zaczniemy przesuwać linie:jjj3k

A zatem:

ggqqqqqjjj3kddjjpkddkkPjddpjj@qq@q
Bogaty
źródło
Dlaczego wyraźnie wyczyściłeś rejestr q? Jeśli tylko zarejestrujesz, wszystko, co tam było, zostanie i tak nadpisane ...
Wildcard
4
@Wildcard Ponieważ jest to makro rekurencyjne, przy pierwszym wywołaniu zawartości rejestru qmusi być puste, w przeciwnym razie zepsuje edycje.
saginaw
Bardzo dobrze. Próbowałem tego interaktywnie, nie wpisując dokładnej sekwencji polecenia, i skończyłem przy użyciu:qqqggqqjjjkddkkPjddjpkddkkPjjjj@qq@q
Wildcard
1
@ablewasiereisawelba where I can just use the one-line custom command each time I need to do this- pamiętaj, że nie trzeba ponownie tworzyć makra za każdym razem, gdy trzeba go użyć, ponieważ można go zapisać jako funkcję / polecenie w vimrc.
mMontu
1
@ablewasiereisawelba Cieszę się, że „Edycja” była przydatna! Ponieważ był to Twój pierwszy post tutaj, być może nie wiesz, jak działają powiadomienia StackExchange: po opublikowaniu komentarza autor odpowiedzi / pytań otrzymuje powiadomienie; inne osoby otrzymają powiadomienie tylko, jeśli podasz @ <nick>. Dlatego tylko Rich otrzymał powiadomienia o twoich ostatnich wiadomościach.
mMontu,
7

Możesz to również zrobić za pomocą Expolecenia używanego sedjako filtr zewnętrzny:

:%!sed -n 'h;n;G;h;n;G;h;n;G;p'

Ta wersja zignoruje (usunie) wszelkie dodatkowe wiersze poza wielokrotnością 4. Aby pozostać w ostatnim zestawie mniej niż 4 wiersze (odwrócone), użyj:

:%!sed -n '$p;h;n;G;$p;h;n;G;$p;h;n;G;p'

%Tutaj oznacza „każda linia w buforze.”

Te !środki polecenia „Uruchom następujące polecenie z określonymi liniami jako wejście, a zastąpić określone wiersze z wyjściem polecenia.” (Nazywa się to filtrem; bardzo przydatny do takich rzeczy jak sortowanie, np. :%!sortSortuje wszystkie linie w twoim pliku; :2,8!sortsortuje linie 2-8 itp.)

sedjest narzędziem do edytowania strumieni i można go znaleźć we wszystkich systemach uniksopodobnych. Kluczowymi pojęciami sedstosowanymi tutaj są „przestrzeń wzorca” (która domyślnie zawiera po prostu każdy wiersz danych wejściowych po kolei) oraz „przestrzeń wstrzymania” (gdzie można wstawić dodatkowy tekst, używając go seddo zapisania go podczas przetwarzania innych wiersze wprowadzania).

-njest opcją dla sedpolecenia, aby ukryć jego domyślne działania drukowania przestrzeni wzorców (ponieważ w tym przypadku chcemy drukować tylko wtedy, gdy wyraźnie to mówimy).

$pw sedpoleceniu oznacza „Jeśli znajdujesz się w ostatnim wierszu sedwejścia, wydrukuj (przestrzeń wzorów).”

h oznacza „przykleić bieżącą zawartość„ przestrzeni wzorów ”do„ przestrzeni wstrzymania ”, zastępując wszystko, co tam jest”.

n oznacza „zamień zawartość„ przestrzeni wzorów ”na następny wiersz z danych wejściowych.”

G oznacza „dołącz do„ przestrzeni wzorów ”: nowa linia, po której następuje treść„ przestrzeni wstrzymania ”.

Podsumowując, sedpolecenie przechowuje cztery wiersze danych wyjściowych, odwracając je podczas przechowywania, a następnie drukuje. Te $ppolecenia dodane w drugiej wersji zapewniają, że jeśli ostatni wiersz pliku zostanie osiągnięty inny niż na wielokrotność 4 linie, linie są nadal drukowane.


Dla alternatywnego, interaktywnego podejścia wciąż bez użycia funkcji specyficznych dla Vima, a także bez użycia zewnętrznego filtra:

:4

przejść do czwartej linii.

:.m -4 | +3m . | +2m . | +5

aby odwrócić poprzednie cztery linie (1-4) i pozostawić kursor w linii 8.

.m -4przesuwa bieżącą linię do tuż po linii cztery linie wstecz (pozostawiając kursor na przesuniętej linii).

+3m .przesuwa linię, która jest 3 linie za bieżącą linią, tuż za bieżącą linią, pozostawiając kursor na przesuniętej linii. +2m .oczywiście działa tak samo.

+5 ustawia kursor pięć linii w dół od miejsca, w którym się znajduje.

Powtórz w razie potrzeby.

W Vimie możesz powtórzyć to polecenie za pomocą @:, a następnie powtórzyć za pomocą @@. W POSIX vilub exciebie musiałby włożyć :.m -4 | +3m . | +2m . | +5 w postaci linii tekstu, usuń ją do określonego bufora (rejestru), a następnie wykonać tę nazwie bufora (rejestr).

Tak więc w extrybie interaktywne odwracanie wierszy tylko przy użyciu funkcji określonych przez POSIX i rozpoczynanie od 17 wierszy tekstu:

Entering Ex mode.  Type "visual" to go to Normal mode.
:0a     # Append following text after "line 0" (i.e. insert at start of file).
.m -4 | +3m . | +2m . | +5
.       # End text insertion
:d k    # Delete that line to register k
line1   # This is a printout of the current line
:4      # Move to line 4
line4
:@k     # Execute register k to reverse lines 1-4
line8
:@@     # Execute register k again
line12
:@@     # Execute register k again
line16
:@@     # Execute register k again
line17
:%p     # Print the whole buffer (just to see what was done)
line4
line3
line2
line1
line8
line7
line6
line5
line12
line11
line10
line9
line16
line15
line14
line13
line17
:wq     # Save and quit

Dalsza lektura:

Dzika karta
źródło
Czy mógłbyś wyjaśnić trochę więcej swojego rozwiązania?
vappolinario
3
@vappolinario, dodałem dalsze wyjaśnienia. To pomaga? :)
Wildcard
Wow, bardzo długa odpowiedź. :) Właściwie to sed, ale użyłem go tylko z jednym prostym skryptem, który gdzieś znalazłem - prawdopodobnie na tej płycie - to było rozwiązanie mojego problemu. Jednak gdy próbowałem uruchomić sugerowaną linię, napis „sed” nie jest rozpoznawany jako wewnętrzna lub zewnętrzna komenda, program operacyjny lub plik wsadowy. ” Nie jestem pewien, czy muszę mieć sed w folderze vim czy co.
ablewasiereisawelba
1
@ablewasiereisawelba, jeśli pracujesz na Windowsie i nie używasz Cygwin (lub MobaXterm lub podobnego), możesz wypróbować inną metodę, którą podałem: 4G:.m -4 | +3m . | +2m . | +5<Enter>@:następnie @@powtarzaj, aż plik zostanie w pełni przetworzony. Polecam jednak instalację MobaXterm. :)
Wildcard
@Wildcard Okay, sprawdzam teraz MobaXterm. :)
ablewasiereisawelba
7
:g/^/exe 'm .-' . substitute(line('.') % 4, '^0$', '4', '')

Zwykły angielski: Dla każdej linii przesuń bieżącą linię w górę lnum % 4, chyba że lnum % 4 == 0w takim przypadku przesuń bieżącą linię w górę 4.

Ponadto, aby odwrócić wszystkie nlinie, zamień 4's w powyższym poleceniu na n.

djjcast
źródło
2
Bardzo ładne polecenie w jednym wierszu. Dziękuję, djjcast.
ablewasiereisawelba