Wie füge ich alle Linien zu welchem ​​passenden Muster zusammen?

11

Ich möchte Linien nur für Linien zusammenfügen, die ein bestimmtes Muster haben (z. B. ;), aber wenn g/;/jsie verwendet werden, funktionieren sie nicht wie erwartet, es sei denn, sie werden mehrmals aufgerufen.

Zum Beispiel den folgenden Inhalt:

a
1;
2;
3;
4;
5;
b
6;
7;
8;
9;
c

bei Verwendung von: :g/;/jdie Ausgabe ist:

a
1; 2;
3; 4;
5; b
6; 7;
8; 9;
c

oder :g/;/-jgibt:

a 1; 2; 3; 4; 5;
b 6; 7; 8; 9;
c

ähnlich mit : :g/;\_.\{-};/j.

Meine erwartete Ausgabe ist:

a 
1; 2; 3; 4; 5;
b
6; 7; 8; 9;
c

oder ähnliches, so dass alle Linien, die das Muster enthalten, miteinander verbunden werden.

Wie kann dies erreicht werden?

Kenorb
quelle
3
FWIW :g/;/jfunktioniert nicht, da dies in zwei Durchgängen erfolgt: Zuerst wird der Puffer gescannt, dann wird der Befehl auf die übereinstimmenden Zeilen angewendet.
Romainl

Antworten:

12

Mögliche Erklärung des Problems

Ich denke, der Grund, warum :g/;/jnicht funktioniert, ist, dass der :gBefehl mit einem 2-Pass-Algorithmus arbeitet:

  • Während des ersten Durchgangs werden die Linien markiert, die das Muster enthalten ;
  • Während des zweiten Durchgangs werden die markierten Linien bearbeitet

:gVerbindet die Linie während des zweiten Durchgangs mit der Linie 1;, 2;da 1;sie während des ersten Durchgangs markiert wurde. Ich vermute jedoch (nicht sicher), dass es nicht 1; 2;mit verbunden ist, 3;da die Zeile 2;nicht mehr existiert. Ihr Inhalt wurde mit der 1;bereits verarbeiteten Zeile zusammengeführt .

So :gsieht für die nächste Zeile , die während der ersten Durchlauf markiert wurde ( 3;) und verbindet es mit dem folgenden ( 4;). Danach das Problem wiederholt, ist es nicht beitreten kann 3; 4;mit , 5;weil die Leitung 4;nicht mehr existiert.

Lösung 1 (mit Vimscript)

Vielleicht können Sie eine Funktion aufrufen, wenn eine Zeile mit ;gefunden wird, um zu überprüfen, ob die vorherige Zeile auch ein Semikolon enthält:

function! JoinLines()
    if getline(line('.')-1) =~ ';'
        .-1join
    endif
endfunction

Verwenden Sie dann den folgenden globalen Befehl:

:g/;/call JoinLines()

Oder ohne Funktion:

:g/;/if getline(line('.')-1) =~ ';' | -j | endif

Lösung 2 (ohne Vimscript)

:g/;/.,/^[^;]*$/-1j

Immer wenn der globale Befehl :gdas Muster findet ;, führt er den Befehl aus: .,/^[^;]*$/-1j

Es kann so aufgeschlüsselt werden:

:g/pattern/a,bj

Wo :

pattern = ;
a       = .           = number of current line
b       = /^[^;]*$/-1 = number of next line without any semicolon minus one

b kann so weiter aufgeschlüsselt werden:

/    = look for the number of the next line matching the following pattern
^    = a beginning of line
[^;] = then any character except a semicolon
 *   = the last character can be repeated 0 or more times
 $   = an end of line
 /   = end of pattern
 -1  = removes one to the number you just got

jist die abgekürzte Form des Ex-Befehls, :joinder wie die meisten anderen Ex-Befehle ein Bereich vorangestellt werden kann.
Hier wird es von dem Bereich voran: .,/^[^;]*$/-1( a,b)
ein Bereich folgt die Form , a,bwo aund im bAllgemeinen 2 Zeilennummern sind, und ermöglicht es auf einer Gruppe von Zeilen , deren Zahl zu betreiben ist zwischen aund b, statt nur einem.

Der jBefehl verbindet also alle Zeilen zwischen dem aktuellen ( a) und dem nächsten, die kein Semikolon minus eins ( b) enthalten.

Weitere Informationen finden Sie unter:

:help :global
:help :join
:help :range
saginaw
quelle
1

Ich mache die ganze Zeit einen ähnlichen Beitritt mit einer globalen Suche und ersetze:

s /; \ n /; /

\n entspricht newline.

So finden und löschen Sie Leerzeilen:

s / ^ $ \ n //

Ich bin nicht sicher warum, aber wenn Sie eine neue Zeile einfügen möchten, müssen Sie verwenden \r

rlh100
quelle
sallein wird nur für eine Zeile funktionieren, um es global zu machen, müssen Sie verwenden %s, aber dann wird es fast alle Zeilen verbinden, einschließlich Nicht- ;Zeilen
Kenorb
2
@kenorb Ehm nein, ich denke, Sie können den :sBefehl genau für das verwenden, was Sie wollen. Ich denke, das %s/;\n\(.*;\)\@=/;/macht was du brauchst.
Christian Brabandt