Vim: String umkehren (nach Wörtern)

8

Das ist mein String:

"this is my sentence"

Ich möchte diese Ausgabe haben:

"sentence my is this"

Ich möchte einige Wörter in einer Zeile (in einem Puffer) auswählen und sie Wort für Wort umkehren.

Kann mir jemand helfen?

    
Reman 03.04.2011, 20:52
quelle

4 Antworten

15

Es ist nicht völlig klar, was der Kontext hier ist: Sie könnten über Text in einer Zeile in einem Puffer oder über eine Zeichenfolge sprechen, die in einer VimScript-Variablen gespeichert ist.

Anmerkung: Unterschiedliche Interpretationen der Frage führten zu verschiedenen Ansätzen und Lösungen.
Es gibt einige " alte Updates ", die ungefähr auf halbem Weg beginnen und durch ein Plugin, das direkt über diesem Abschnitt erwähnt wird, mehr oder weniger veraltet sind. Ich habe sie zurückgelassen, weil sie für einige Leute nützliche Informationen liefern können.

Ersetzen der vollständigen Zeile

Um den Text aus der aktuellen Zeile im aktuellen Puffer in einer vimscript-Variablen zu speichern, tun Sie dies

%Vor%

Und dann, um ihre Reihenfolge umzukehren, tun Sie einfach

%Vor%

Wenn Sie die aktuelle Zeile durch die umgekehrten Wörter ersetzen möchten, tun Sie

%Vor%

Sie können es in einer etwas undurchschaubaren Zeile mit

machen %Vor%

oder definieren Sie sogar einen Befehl, der das mit

macht %Vor%

Teilzeichen (zeichenweise) Selektionen

Wie unten im Abschnitt "alte Updates" erklärt, kann das Ausführen allgemeiner Befehle für eine zeichen- oder blockweise visuelle Auswahl - die erste ist das, was das OP hier machen will - ziemlich kompliziert sein. Ex-Befehle wie :substitute werden auf ganzen Zeilen ausgeführt, auch wenn nur ein Teil der Zeile ausgewählt ist Verwenden einer zeichenweisen visuellen Auswahl (wie mit einem unverschobenen v eingeleitet).

Ich erkannte, dass nach dem unten erwähnten OP die Umkehrung der Wörter in einer teilweisen zeichenartigen Auswahl ziemlich einfach mit

erreicht werden kann %Vor%

wobei

  • \%V in der RE stimmt mit einem Teil der visuellen Auswahl überein. Offensichtlich geht dies nicht nach dem letzten Zeichen in der Auswahl: Das Auslassen der letzten . schließt das zuletzt ausgewählte Zeichen aus.
  • \= zu Beginn der Ersetzung zeigt an, dass es als a ausgewertet werden soll vimscript-Ausdruck mit einigen Unterschieden .
  • submatch(0) gibt das gesamte Match zurück. Das funktioniert ein bisschen wie perl's $& , , usw., außer dass es nur verfügbar ist, wenn die Ersetzung ausgewertet wird. Ich denke, das bedeutet, dass es nur in einem :substitute -Befehl oder in einem Aufruf von substitute() verwendet werden kann.

Wenn Sie also bei einer einzeiligen Auswahl eine Ersetzung vornehmen möchten, funktioniert das ganz gut. Sie können die Auswahl sogar über einen Systembefehl mit ...\=system(submatch(0)) weiterleiten.

mehrzeilige zeichenweise Auswahl

Dies scheint auch bei einer mehrzeiligen zeichenweisen Auswahl zu funktionieren, aber Sie müssen vorsichtig sein, um den Bereich zu löschen (das '<,'> , das vim am Anfang eines Befehls setzt, wenn es vom visuellen Modus kommt). Sie möchten den Befehl nur in der Zeile ausführen, in der Ihre visuelle Auswahl beginnt. Sie müssen auch \_.* anstelle von .* verwenden, um über neue Zeilen zu passen.

blockweise Auswahl

Bei blockweisen Auswahlen glaube ich nicht, dass es eine vernünftige Möglichkeit gibt, sie zu manipulieren. Ich habe ein Plugin geschrieben, das verwendet werden kann, um diese Art von Änderungen weniger schmerzhaft zu machen, indem es eine Möglichkeit bietet, beliebige Ex-Befehle auf jeder visuellen Auswahl auszuführen, als ob es der gesamte Pufferinhalt wäre.

Es ist verfügbar unter Ссылка . Momentan gibt es keine Verpackung, und es ist noch nicht auf vim.org verfügbar, aber Sie können einfach git clone it und kopieren den Inhalt (abzüglich der README-Datei) in Ihr vimdir.

Wenn Sie vim-addon-manager verwenden, klonen Sie einfach visdo in Ihrem vim-addons-Verzeichnis und Sie ' Anschließend können Sie ActivateAddons visdo . Ich habe eine Anfrage gestellt, sie dem VAM addons-Repository hinzufügen zu lassen, damit Sie irgendwann auf das Klonen verzichten können und einfach ActivateAddons visdo machen.

Das Plugin fügt einen :VisDo -Befehl hinzu, der einem anderen Befehl vorangestellt werden soll (ähnlich wie :tab oder :silent funktioniert). Wenn Sie einen Befehl mit VisDo prepended ausführen, wird dieser Befehl in einem Puffer ausgeführt, der nur den aktuellen Inhalt der visuellen Auswahl enthält. Nachdem der Befehl abgeschlossen ist, wird der Inhalt des Puffers in die visuelle Auswahl des ursprünglichen Puffers eingefügt und der temporäre Puffer wird gelöscht.

Um das Ziel des OPs mit VisDo zu vervollständigen, müssten Sie also (mit den zu invertierenden Wörtern und mit dem oben definierten Befehl ReverseLine):

%Vor%

alte Updates

... vorherige Updates folgen ... Warnung: ausführlich, etwas obselet und meistens unnötig ...

Die Bearbeitung des OP verdeutlicht, dass das Ziel darin besteht, die in einer visuellen Auswahl enthaltenen Wörter und insbesondere eine zeichenweise visuelle Auswahl umzukehren.

Dies ist entschieden keine einfache Aufgabe. Die Tatsache, dass vim solche Dinge nicht einfach macht, verwirrte mich wirklich, als ich anfing, es zu benutzen. Ich denke, das liegt daran, dass seine Wurzeln immer noch sehr stark in der zeilenorientierten Bearbeitungsfunktion von ed und seinen Vor- und Nachläufern liegen. Zum Beispiel wird der Ersatzbefehl :'<,'>s/.../.../ immer an ganzen Zeilen arbeiten, auch wenn Sie sich im zeichenweisen oder blockweisen ( ctrl v ) visuellen Auswahlmodus befinden.

Vimscript macht es möglich, die Spaltennummer irgendeines "Zeichens" zu finden, einschließlich des Beginns der visuellen Auswahl ( '< ) und des Endes der visuellen Auswahl ( '> ). Das heißt, soweit ich das beurteilen kann, die Grenze seiner Unterstützung. Es gibt keinen direkten Weg, um den Inhalt der visuellen Auswahl zu erhalten, und es gibt keine Möglichkeit, die visuelle Auswahl durch etwas anderes zu ersetzen. Natürlich können Sie diese beiden Dinge auch mit normalen Befehlen ( y und p ) machen, aber diese Clobbers registrieren sich und sind irgendwie unordentlich. Aber dann können Sie die Anfangsregister speichern und dann nach dem Einfügen wiederherstellen ...

Sie müssen also im Grunde genommen extreme Längen mit Teilen von Linien machen, was mit ganzen Linien leicht gemacht werden kann. Ich vermute, dass der beste Weg dies zu tun ist, einen Befehl zu schreiben, der die visuelle Auswahl in einen neuen Puffer kopiert, einen anderen Befehl ausführt und dann die visuelle Auswahl des ursprünglichen Puffers durch die Ergebnisse ersetzt und den temporären Puffer löscht. Dieser Ansatz sollte theoretisch sowohl für zeichenorientierte als auch für blockweise Auswahl sowie für die bereits unterstützten linienweisen Auswahlmöglichkeiten funktionieren. Das habe ich aber noch nicht gemacht.

Dieser Code-Chunk mit 40 Zeilen deklariert einen Befehl ReverseCharwiseVisualWords , der aus dem visuellen Modus aufgerufen werden kann. Es funktioniert nur, wenn die zeichenweise visuelle Auswahl vollständig auf einer einzigen Zeile ist. Es funktioniert, indem die gesamte Zeile mit der visuellen Auswahl (mit getline() ) eine parametrisierte Transformationsfunktion ( ReverseWords ) für den ausgewählten Teil davon ausführt und die gesamte teilweise transformierte Zeile wieder einfügt. Im Nachhinein denke ich, dass es sich wahrscheinlich lohnt, die Route y / p für etwas, das ausführlicher ist, zu gehen.

%Vor%

update 2

Es stellt sich heraus, dass es viel einfacher ist, Dinge mit y und p zu erledigen, also dachte ich, ich würde das auch posten. Vorbehalt: Ich habe das nicht allzu gründlich getestet, daher kann es Grenzfälle geben.

Diese Funktion ersetzt TransformCharwiseVisual (und einige ihrer Abhängigkeiten) im vorherigen Codeblock. Es sollte theoretisch auch für blockweise Selektionen funktionieren - es liegt an der übergebenen Transform -Funktion, entsprechende Dinge mit Zeilenbegrenzern zu tun.

%Vor%

Also können Sie einfach eine zweite Befehlsdeklaration hinzufügen

%Vor%

tangential verwandtes blutiges Detail

Beachten Sie, dass der Nutzen einer Funktion auf höherer Ebene, wie sie hier verwendet wird, durch die Tatsache begrenzt ist, dass es keine (einfache oder etablierte) Möglichkeit gibt, eine Inline-Funktion oder einen Block von Code in vimscript zu deklarieren. Dies wäre keine Einschränkung, wenn die Sprache nicht interaktiv verwendet werden sollte. Sie könnten eine Funktion schreiben, die ihr String-Argument in eine Dictionary-Funktionsdeklaration einfügt und die Funktion zurückgibt. Dictionary-Funktionen können jedoch nicht mit der normalen Aufrufsyntax aufgerufen werden und müssen an call call(dictfunct, args, {}) übergeben werden.

Hinweis: Ein neueres Update, wie oben angegeben, macht den obigen Code überflüssig. Sehen Sie sich die verschiedenen Abschnitte an, die den alten Updates vorangehen , um einen einfacheren Weg zu finden.

    
intuited 03.04.2011, 21:04
quelle
1

Vielleicht:

%Vor%

Natürlich müssen Sie im ersten Teil wahrscheinlich genauer sein, um diesen bestimmten Satz zu finden. Im Allgemeinen können Sie Match-Gruppen als \ number bezeichnen, wobei \ 0 das ganze Match ist.

    
Tamás Szelei 03.04.2011 20:55
quelle
1

Hier können Sie Ruby anrufen. Nachdem Sie die Zeile ausgewählt haben, die Sie umkehren möchten, können Sie dies im Befehlsmodus tun, um sie zu ersetzen:

%Vor%     
kejadlen 03.04.2011 23:20
quelle
1

Ich fand die Lösung selbst dank Ihrer Antworten und vielen Versuchen:)

Das funktioniert:

function! Test()
exe 'normal ' . 'gv"ay'
let r = join(reverse(split(getreg('a'))))
let @a = r
exe 'normal ' . 'gv"ap'
endfunction

Dachte nicht, dass ich eine solche Funktion schreiben könnte:)

    
Reman 04.04.2011 14:41
quelle

Tags und Links