Wie alle 4 Zeilen umkehren?

13

Da dies mein erster Beitrag hier ist, möchte ich nur sagen, dass VIM ein großartiges Tool ist und das Forum hier sehr hilfreich ist, um Antworten auf Fragen zu finden, und viele hilfreiche Leute zur Verfügung stehen unschätzbare Hilfe. Ich bin noch sehr neu in VIM, so ziemlich alles, was ich darüber gelernt habe, ist von hier gekommen.

Meine Frage ist: Ich weiß, wie man ALLE Zeilen in einer Datei umkehrt (: g / ^ / m0 unter anderem), aber gibt es eine Möglichkeit, alle 4 Zeilen in einer Datei umzukehren, so dass

line1
line2
line3
line4
line5
line6
line7
line8
...

wird

line4
line3
line2
line1
line8
line7
line6
line5
...

Sie können davon ausgehen, dass solche Dateien immer ein genaues Vielfaches von 4 Zeilen enthalten.

ablewasiereisawelba
quelle
2
Zu Ihrem "ps": Wenn Sie 4 Leerzeichen vor einer Zeile einfügen, wird dies als Code interpretiert (Sie können den Text auswählen und die Formatierungsschaltflächen oben verwenden). Weitere Details finden Sie auf dem Abfragesymbol oben .
MMontu

Antworten:

15

Der :Reverseim Vim Wiki erläuterte Befehl kann dazu verwendet werden (Sie können ihn in Ihren Befehl aufnehmen , .vimrcum ihn dauerhaft zu machen):

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

Anschließend können Sie ein Makro aufzeichnen, um den Befehl alle vier Zeilen auszuführen:

qmV3j:Reverse<cr>4jq
1000@m

Erläuterung:

  • qm: 'q' im normalen Modus startet (und stoppt) die Aufzeichnung eines Makros in einem bestimmten Register (Register 'm', in diesem Fall kann es sich jedoch auch um einen anderen Buchstaben handeln)
  • V: Ruft den visuellen Modus auf und wählt die aktuelle Zeile aus
  • 3j: Erweitern Sie die visuelle Auswahl auf die nächsten 3 Zeilen
  • :Reverse<cr>: Führen Sie den Befehl Umkehren in den ausgewählten Zeilen aus ( <cr>hier steht für den enterSchlüssel)
  • 4j: gehe zu den nächsten unveränderten Zeilen
  • q: Stoppt die Aufzeichnung des Makros
  • 1000@m: Führen Sie das im Register 'm' aufgezeichnete Makro 1000 Mal aus (Sie können diese Zahl erhöhen, wenn Ihre Datei größer als 4000 Zeilen ist).

Bearbeiten:

Wie in den Kommentaren erwähnt, können Sie anstelle einer Zählung auch ein rekursives Makro verwenden:

qmV3j:Reverse<cr>4jq
qM@mq
@m
  • qM: Wenn das angegebene Register qin Großbuchstaben geschrieben ist, wird das Makro an das Register angehängt. Dies ist auch hilfreich, wenn Sie feststellen, dass Sie die letzten Schritte eines komplexen Makros verpasst haben.
  • @m: Führe das Makro im Register aus m
  • q: Hänge das Makro nicht mehr an

Obwohl es als Makro erstellt wurde, können Sie einen Befehl dafür erstellen, wenn dies eine häufige Aufgabe in Ihrem Workflow ist:

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: Definiert eine neue Funktion
  • let reg_m = @m: speichert den aktuellen Inhalt des Registers m
  • let @m = "<c-r><c-r>m": Bitte geben Sie den Makro in dem Register m- beachten Sie, dass <c-r>die vim Notation für ist Ctrl+ rund dass Sie geben diese, kopieren Sie nicht / einfügen, so dass Ihre Linie zu ähnlich sein wird , let @m = 'V3j:Reverse^M4j@m'und es wird ein enthaltenes Sonderzeichen (^ M)
  • normal! @m: Der normale Befehl führt sein Argument so aus, wie es im normalen Modus eingegeben wurde, und führt das rekursive Makro aus
  • let @m = reg_m: stellt den Inhalt des Registers wieder her m, sodass Sie sich nicht daran erinnern müssen, dass dieses Register für diese Funktion verwendet wird, und vermeiden, es zu verwenden

  • command! Reverse4 call Reverse4(): Erstellt einen neuen Befehl für diese Funktion

Abhängig von Ihren Anforderungen können Sie es erweitern, z. B .: Übergeben Sie ein Argument an den Befehl und die Funktion, damit es für eine beliebige Anzahl von Zeilen funktioniert, anstatt in Gruppen von 4 Zeilen festgelegt zu werden.

mMontu
quelle
Anstelle des 1000@qHack, können Sie auch eine rekursive Makro verwenden: qmqqm ... @mq@m.
Türknauf
Als ich versuchte, "qmV3j: Reverse <cr> 4jq" auszuführen, wurde "E492: Not an editor command" angezeigt. Ich muss etwas falsch machen. Ich benutze übrigens GVIM - und habe es immer nur benutzt. Ich hätte das an erster Stelle erwähnen sollen.
ablewasiereisawelba
Ah vergiss es. Ich habe es herausgefunden - ich soll nicht ":" vor dem Teil "qmV3j: Reverse <cr> 4jq" eingeben. Es funktionierte! Vielen Dank, mMontu. Wenn ich fragen darf - wie füge ich den Befehl ": Reverse" in meine .vimrc ein?
ablewasiereisawelba
3
@ablewasiereisawelba Um den Befehl dauerhaft verfügbar zu machen, schreiben Sie einfach die Zeile command! -bar -range=% Reverse <line1>,<line2>g/^/m<line1>-1|nohlirgendwo in Ihren vimrc.
Saginaw
@saginaw Oh, ich wusste nicht, dass es so einfach ist. Vielen Dank.
ablewasiereisawelba
9

Wie bei allen sich wiederholenden Aktionen können Sie auch bei grundlegenden Bearbeitungsvorgängen einige Vorgänge problemlos ausführen, indem Sie ein Makro aufzeichnen.

(In diesem Fall verwende ich ein rekursives Makro, aber Sie können einfach ein nicht rekursives Makro aufzeichnen und es durch Hämmern @@oder Verwenden einer Zählung mehrmals wiedergeben .)

ggqqqqqddjjpkddkkPjddpjj@qq@q

Heruntergebrochen

  1. gg: Zum Anfang der Datei gehen.
  2. qqq: Register löschen q. Wir werden in Schritt 5 sehen, warum dies notwendig ist.
  3. qq: Starten Sie die Aufzeichnung eines Makros, um q zu registrieren
  4. ddjjpkddkkPjddpjj: Eine Reihe von Vorgängen, bei denen die ersten vier Zeilen einfach durch manuelles Löschen und Einfügen neu angeordnet werden. (Dies könnte auf den ersten Blick kompliziert, aber nicht täuschen Diese sehr grundlegende Dinge ist , dass Sie in den ersten 5 Minuten oder so von gelernt haben würde. vimtutor: j, k, dd, p, P)
  5. @q: Rufe das Makro auf! Zu diesem Zeitpunkt qenthält das Register noch nichts (da wir es in Schritt 2 gelöscht haben), sodass nichts passiert.
  6. q: Beenden Sie die Aufzeichnung des Makros.
  7. @q: Wiederholen Sie das rekursive Makro so oft wie nötig.

Hinweis: Das oben Genannte führt nicht zu den gewünschten Ergebnissen, wenn die Datei eine Anzahl von Zeilen enthält, die nicht genau durch vier teilbar sind. Um das Makro vorzeitig zu stoppen, wenn keine vier Zeilen mehr vorhanden sind, müssen Sie einen Vim-Befehl im Normalmodus ausführen, der fehlschlägt, bevor Sie die Änderungen in Schritt 4 anwenden. Versuchen Sie dazu, nach unten zu springen eine Zeile dreimal (und dann wieder hoch), bevor wir beginnen, Zeilen zu verschieben:jjj3k

Somit:

ggqqqqqjjj3kddjjpkddkkPjddpjj@qq@q
Reich
quelle
Warum löschen Sie das Register q explizit aus? Wenn Sie nur darauf aufnehmen, wird das, was sich dort befand, sowieso überschrieben.
Wildcard
4
@Wildcard Da es sich um ein rekursives Makro handelt, qmuss der Inhalt des Registers beim ersten Aufruf leer sein, da er sonst Ihre Ausgaben durcheinander bringt.
Saginaw
Sehr schön. Ich habe dies interaktiv versucht, ohne zu versuchen, die genaue Reihenfolge Ihres Befehls einzugeben, und habe Folgendes verwendet:qqqggqqjjjkddkkPjddjpkddkkPjjjj@qq@q
Wildcard
1
@ablewasiereisawelba where I can just use the one-line custom command each time I need to do this- Beachten Sie, dass Sie das Makro nicht jedes Mal neu erstellen müssen, wenn Sie es verwenden möchten, da es auf Ihrem vimrc als Funktion / Befehl gespeichert werden kann.
MMontu
1
@ablewasiereisawelba Ich bin froh, dass Sie das "Bearbeiten" nützlich fanden! Da dies Ihr erster Beitrag hier war, wissen Sie möglicherweise nicht, wie StackExchange-Benachrichtigungen funktionieren: Wenn Sie einen Kommentar veröffentlichen, erhält der Autor der Antwort / der Fragen eine Benachrichtigung. andere Personen erhalten eine Benachrichtigung nur, wenn Sie das @ <nick> angeben. Somit hat nur Rich Benachrichtigungen über Ihre letzten Nachrichten erhalten.
MMontu
7

Sie können dies auch mit einem ExBefehl tun , der sedals externen Filter verwendet wird:

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

Diese Version ignoriert (löscht) alle zusätzlichen Zeilen, die ein Vielfaches von 4 überschreiten. Um den letzten Satz von weniger als 4 Zeilen (umgekehrt) beizubehalten, verwenden Sie:

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

Das %hier bedeutet "Jede Zeile im Puffer".

Der !Befehl bedeutet "Führen Sie den folgenden Befehl mit den angegebenen Zeilen als Eingabe aus und ersetzen Sie die angegebenen Zeilen durch die Ausgabe des Befehls." (Es wird als Filter bezeichnet. Sehr praktisch, wenn Sie beispielsweise sortieren, um beispielsweise :%!sortalle Zeilen in Ihrer Datei zu :2,8!sortsortieren, oder um die Zeilen 2 bis 8 usw. zu sortieren.)

sedist das Stream-Editor- Tool und ist auf allen Unix-ähnlichen Systemen zu finden. Die wichtigsten hier verwendeten Konzepte sedsind der "Musterbereich" (der standardmäßig nur die einzelnen Zeilen der Eingabe enthält) und der "Haltebereich" (in dem Sie zusätzlichen Text sedeinfügen können, während Sie ihn speichern, während Sie andere verarbeiten) Eingabezeilen).

-nist eine Option für den sedBefehl, um seine Standardaktionen zum Drucken des Musterbereichs zu unterdrücken (da wir in diesem Fall nur drucken möchten, wenn wir dies ausdrücklich sagen.)

$pim sedBefehl bedeutet "Wenn Sie in der letzten Zeile der sedEingabe sind, drucken Sie (das Muster Leerzeichen)."

h bedeutet "den aktuellen Inhalt des 'Pattern Space' in den 'Hold Space' stecken und überschreiben, was auch immer da ist."

n bedeutet "Ersetzen Sie den Inhalt des 'Musterraums' durch die nächste Zeile der Eingabe."

G bedeutet "an den 'Musterraum' anhängen: eine neue Zeile, gefolgt vom Inhalt des 'Halteraums'."

Insgesamt sedspeichert der Befehl vier Ausgabezeilen, kehrt sie beim Speichern um und druckt sie dann aus. Die $pin der zweiten Version hinzugefügten Befehle stellen sicher, dass die Zeilen weiterhin gedruckt werden, wenn die letzte Zeile der Datei anders als in einem Vielfachen von 4 Zeilen erreicht wird.


Für einen alternativen, interaktiven Ansatz, bei dem noch keine Vim-spezifischen Funktionen und auch kein externer Filter verwendet werden:

:4

in die vierte Zeile gehen.

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

Um die vorherigen vier Zeilen (1-4) umzukehren und den Cursor in Zeile 8 zu lassen.

.m -4Verschiebt die aktuelle Zeile um vier Zeilen nach der Zeile zurück (wobei der Cursor auf der verschobenen Zeile verbleibt).

+3m .Verschiebt die Zeile, die 3 Zeilen nach der aktuellen Zeile liegt, direkt nach der aktuellen Zeile, wobei der Cursor auf der verschobenen Zeile verbleibt. +2m .funktioniert natürlich genauso.

+5 Platziert den Cursor fünf Zeilen nach unten.

Wiederholen Sie diesen Vorgang wie gewünscht.

In Vim können Sie den gesamten Befehl mit @:und anschließend mit wiederholen @@. In POSIX vioder müssen exSie als Textzeile einfügen :.m -4 | +3m . | +2m . | +5 , löschen Sie es in einen benannten Puffer (Register) und führen Sie dann diesen benannten Puffer (Register) aus.

Im exModus können Sie also Zeilen interaktiv umkehren, indem Sie nur von POSIX angegebene Features verwenden und mit 17 Textzeilen beginnen:

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

Weitere Lektüre:

Platzhalter
quelle
Können Sie uns Ihre Lösung etwas näher erläutern?
Vappolinario
3
@vappolinario, ich habe eine weitere Erklärung hinzugefügt. Hilft das? :)
Wildcard
Wow, sehr lange Antwort. :) Eigentlich habe ich sed, aber ich habe es nur mit einem einfachen Skript verwendet, das ich irgendwo gefunden habe - wahrscheinlich auf dieser Tafel -, das war eine Lösung für ein Problem, das ich hatte. Als ich jedoch versuchte, Ihre vorgeschlagene Zeile auszuführen, wurde "sed" nicht als interner oder externer Befehl, ausführbares Programm oder Batch-Datei erkannt. " Ich bin mir nicht sicher, ob ich den vim-Ordner haben muss oder was.
ablewasiereisawelba
1
@ablewasiereisawelba, wenn Sie auf einer Windows-Box laufen und Cygwin (oder MobaXterm oder ähnliches) nicht verwenden, können Sie die andere Methode ausprobieren, die ich angegeben habe: 4G:.m -4 | +3m . | +2m . | +5<Enter>@:Dann @@wiederholen, bis Ihre Datei vollständig verarbeitet ist. Ich empfehle jedoch die Installation von MobaXterm. :)
Wildcard
@Wildcard Oh okay, ich checke gerade MobaXterm aus. :)
ablewasiereisawelba
7
:g/^/exe 'm .-' . substitute(line('.') % 4, '^0$', '4', '')

Plain English: Verschieben Sie für jede Zeile die aktuelle Zeile nach oben lnum % 4, es sei denn lnum % 4 == 0, in diesem Fall wird die aktuelle Zeile nach oben verschoben 4.

nUm alle Zeilen umzukehren , ersetzen Sie die 4im obigen Befehl angegebenen durch n.

djjcast
quelle
2
Sehr schöner einzeiliger Befehl. Vielen Dank, DJJCAST.
ablewasiereisawelba