Verschachtelte übereinstimmende Gruppe in Regex


8

Ich habe einen häufigen Anwendungsfall, wenn ich einen Python-Ausdruck folgendermaßen transformiere:

value 1
value 2
value 3

in

['value 1', 'value 2', 'value 3']

Der einfachste Weg ist vielleicht, ein Mapping zu verwenden, aber ich wollte eine Ersetzung für diese Aufgabe verwenden.

Bisher habe ich:

s/\(.*\n\)\+/[&]/g

Welches Ergebnis in

[value 1
value 2
value 3
]

Dies wirft eine Frage auf, weil ich in der Lage sein möchte, das \(.*\), aber nicht das \nund das Ergebnis des Abgleichs innerhalb eines zu vergleichen '...'.

Wissen Sie, wie das geht?


2
Ich weiß nicht, wie es in einer einzelnen Substitution gemacht werden soll, aber Sie könnten es in 2 machen, während Sie sich im visuellen Modus befinden (nachdem Sie den Python-Ausdruck ausgewählt haben): :'<,'>s/\v(.*)\n/'\1', / | s/\v(.*), /[\1]/Sie könnten dies in eine visuelle Zuordnung umwandeln: xnoremap ,x :s/\v(.*)\n/'\1', / <Bar> s/\v(.*), /[\1]/<CR>und möglicherweise in eine normale Zuordnung, wenn die Ausdruck befindet sich in einem Absatz: nnoremap ,x :'{+1,'}-1s/\v(.*)\n/'\1', / <Bar> s/\v(.*), /[\1]/<CR>Hier wäre die Zuordnung ,x.
user9433424

1
konnte nicht mit Regex tun, sondern mit externen Befehlen:%! echo "[$(sed "s/.*/'&',/" % | tr '\n' ' ' | sed 's/, $//')]"
Sundeep

Antworten:


5

Bearbeiten

Es ist möglich, dies in einem Ausdruck zu tun, wenn wir einen "Sub-Replace-Ausdruck" verwenden. Informationen dazu finden Sie unten.

/Bearbeiten

Das Problem hierbei ist, dass Sie zwei verschiedene Dinge tun möchten.

  1. Bearbeiten Sie das Spiel als Ganzes (dh umgeben Sie es mit [])

  2. Betreibe jeden Gegenstand im Match (dh umgib ihn mit '',)

Sie können ganz einfach eines von beiden tun:

  1. :s/\(.\+\n\)\+/[&]/
  2. :%s/\(.\+\)\n/'\1', /

Aber soweit ich weiß, gibt es keine Möglichkeit, beides in einer einzigen Operation zu tun. Ich habe versucht, die richtige Ausgabe mit so etwas wie:

:s/\(\(.\+\)\n\)\+/[\2]/

Aber das Problem dabei ist natürlich, dass die \2Übereinstimmungen nur mit der letzten Übereinstimmung aus dem zweiten Satz von Speicherklammern übereinstimmen \(\)und sich vorher an nichts "erinnern". Sie haben also nur die letzte Zeile.

Ich würde empfehlen, eine Vor- / Nachbearbeitung mit einem zusätzlichen :s///Befehl durchzuführen, um die Zeilenumbrüche vor / nach der Tat zu entfernen. Folgendes habe ich mir ausgedacht

function! FormatExpression()
   .,/\n^$/s/\(.*\)\n/'\1', /
   s/\(.*\), /[\1]/
endfunction

1. Zeile (Zeilenumbrüche entfernen)

  • .,/\n^$/Dies ist ein Bereichsmodifikator für das Suchen und Ersetzen. Ohne dies wird der Befehl fortfahren, um Ihre gesamte Datei zu verstümmeln. Derzeit geht es von der aktuellen Zeile .zur nächsten leeren Zeile \n^$. Ich bin mir nicht sicher, wie Sie die Dinge aufteilen wollten, aber Sie brauchen eine Möglichkeit, es anzuhalten.
  • s/ Der Beginn eines Such- und Ersetzungsbefehls
  • \(.*\)\n Passen Sie die gesamte Zeile an, speichern Sie jedoch nur das Teil ohne die neue Zeile.
  • '\1', Ersetzen Sie die Zeile durch die Übereinstimmung, die von einfachen Anführungszeichen umgeben ist, und fügen Sie ein Komma hinzu.

2. Zeile (Surround in Klammern)

  • \(.*\), Passen Sie die gesamte Zeile an, aber nicht das letzte Komma und Leerzeichen
  • [\1] Mit Klammern umgeben und überflüssiges Endkomma und Leerzeichen entfernen.

Ich werde mich weiter damit befassen, aber im Moment denke ich nicht, dass es mit einem einzigen Ausdruck möglich ist. :(

BEARBEITEN:

Ich habe einen Weg gefunden, dies mit einem Ausdruck zu tun! Intern ist dies eigentlich zwei Substitutionen, aber es ist technisch ein Ausdruck. Folgendes habe ich mir ausgedacht:

:s/\v((.+\n)*.+)\n/\= "['" . substitute(submatch(1), '\n', "', '", 'g') . "']" /
  • :s///: Ersetzen Sie
  • \v((.+\n)*.+)\n: Sammelt im Grunde alle nächsten nicht leeren Zeilen und speichert alles bis auf das Finale \n
  • \=Ermöglicht die Verwendung eines Ausdrucks im Ersatz (siehe :h sub-replace-expression)
  • substitute(submatch(1)...): Ersetzt alle gespeicherten \nmit', '
  • "['" . ... . "']": Vorangestellt ['und angehängt']

Dies beginnt an der Position des Cursors und geht so lange, bis eine leere Zeile ( ^\n) gefunden wird. Es \nist wichtig, nicht den letzten zu greifen, da wir ohne dieses Bit ein zusätzliches übrig haben ',, das wir am Ende nicht wollen.

Einige mögen dies als komplexer betrachten als die vorherige Antwort mit zwei Ausdrücken. Aber ich dachte, ich würde weitermachen und dies hinzufügen, da es tatsächlich möglich ist, es mit einem Ausdruck zu tun. :) :)


2

Optisch hervorheben, dann:

:'<,'> s/.*/['&']/ | *j! | s/]\[/, /ge

Es umgibt jede Zeile, z. B. ['value 1']verbindet sie alle, ersetzt dann benachbart ]und [durch Komma-Leerzeichen.

Die Dokumentation für das *In *j!ist :help cpo-starübrigens bei. Das ist etwas schwierig zu finden.


Gute

Eigentlich können Sie die Verbindung verwenden :'<,'>s/\v(.*)(\_.)/['\1']/und entfernen.
nobe4

Ja, aber es frisst das Finale \n, deshalb habe ich es benutzt :join. Ich hätte das wahrscheinlich erwähnen sollen. :-)
Antony

1
Wie wäre es '<,'>s/.*/['&']/ | *s/]\_.\[/, /dann?
nobe4

1
Ja, das ist besser. Obwohl ich den zweiten Teil wahrscheinlich als schreiben würde *s/]\n\[/, /e.
Antony
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.