Was ist der Unterschied zwischen den Atomen '\ zs' und '\ @ <=' in Vim Regex?

11

Folgendes erhalte ich aus der Dokumentation: \zs"Startet den hervorgehobenen Teil" nach dem Abgleichen des vorhergehenden regulären Ausdrucks und \@<="Startet den hervorgehobenen Teil" nach dem Abgleichen des vorhergehenden Atoms . Aber ich verstehe die Feinheiten nicht genau. Kann jemand erklären, wie sie sich etwas tiefer unterscheiden?

Das hat mich neugierig gemacht: Wenn ich renne

/\_s\zsnnoremap

dh wählt nnoremapvoraus durch ein Leerzeichen oder ein Start-of-line (dh die Neue - Zeile von der vorhergehenden Zeile, damit die \_vor der s) und führte gnVisual Mode einzugeben und visuell auswählen das nächste Spiel, aus irgendeinem Grunde nur die erste Spalte (dh Das erste nin nnoremap) wird ausgewählt - trotz der Tatsache, dass das gesamte nnoremapWort mit aktiviert markiert ist :hlsearch.

Allerdings, wenn ich stattdessen die Suche starte

/\_s\@<=nnoremap

und dann versuchen gn, das Ganze nnoremapist richtig ausgewählt. Was könnte hier los sein? Habe ich (wage ich zu sagen) einen obskuren Fehler entdeckt?

Luke Davis
quelle
Ich denke, es ist in, :h patternsaber mein Gedächtnis legt nahe, dass Regexs aus Atomen bestehen, wenn dies hilft, den Unterschied zu erklären.
D. Ben Knoble

Antworten:

15

Es sieht so aus, als hätten Sie tatsächlich einen obskuren Fehler gefunden. Ich habe das gnTextobjekt schon 2012 für Vim 7.3 etwas implementiert . Grundsätzlich funktioniert es folgendermaßen:

1) Es wird rückwärts nach der letzten Übereinstimmung des aktuellen regulären Ausdrucks gesucht.

2) Es wird nach der nächsten Übereinstimmung des aktuellen regulären Ausdrucks gesucht.

Dies sollte klarstellen, dass sich der Cursor zu Beginn des nächsten Spiels befindet, auch wenn er bereits zu Beginn von 1) vorhanden war. Schließlich

3) es sucht nach dem Ende des aktuellen regulären Ausdrucks. und setzt den Cursor dort.

Was jetzt hier passiert, ist, dass die Suche nach dem Ende des aktuellen Spiels umgeht und zum Ende des vorherigen Spiels zurückkehrt (weil wrapscanbereits festgelegt, nachdem es für 1 deaktiviert wurde). Anschließend wird die visuelle Markierung auf den Bereich von Anfang an (Ende von Punkt 2) und den Bereich gesetzt, in den das nächste Suchelement 3 verschoben wurde.

Ich werde mir das Problem genauer ansehen und wahrscheinlich später einen Patch für Vim einreichen.

[Update 22.05.2018] Ich habe einen Patch geschrieben und eingereicht , um dieses Verhalten zu beheben.

[Update2 22.05.2018] Und der Patch wurde als Patch Level 8.1.0018 zusammengeführt

[Update 22.10.2019] Ab Vim Patch 8.1.629 wird der dritte Schritt nicht mehr ausgeführt. Stattdessen kann Vim jetzt das Ende des Spiels bestimmen, wenn er den Beginn des Spiels findet (Schritt 2).

Christian Brabandt
quelle
8

Christian hat sich vollständig mit der Frage des Buggy-Verhaltens von befasst gn, aber es gibt immer noch grundlegende Unterschiede zwischen \zsund \@<=. Das größte Wesen \@<=modifiziert ein vorhergehendes Atom, während \zses ein Atom in sich selbst ist.

Erwägen:

Xnnoremap

\%1cX\zsnnoremap     (regex 1)
\%1cX\@<=nnoremap    (regex 2)
\%2cX\@<=nnoremap    (regex 3)

Regex 1 stimmt überein, da \%1cSpalte 1 übereinstimmt und dort ein X steht. \zsbewirkt lediglich, dass die Übereinstimmung an einer Position nach dem X neu gestartet wird.

Regex 2 stimmt jedoch nicht überein, da es zwar \%1cmit der ersten Spalte übereinstimmt, X\@<=jedoch eine Breite von Null hat (wie in der Dokumentation erwähnt) und nnoremapbei Spalte 2 beginnt. Es gibt nichts, was den Positionsunterschied zwischen den Spalten 1 und 2 ausgleichen könnte.

Regex 3 stimmt überein, da nnoremapin Spalte 2 begonnen wird.

Masse
quelle
1
Ich glaube nicht, dass der reguläre Ausdruck 2 fehlschlägt, da der Positionsunterschied zwischen den Spalten 1 und 2 nicht ausgeglichen werden kann. Wenn dies das Problem wäre, würde das Entfernen nnoremapaus dem regulären Ausdruck eine Übereinstimmung ergeben. aber der reguläre Ausdruck schlägt auch ohne fehl. Ich denke, es schlägt fehl, weil \%1cX\@<=es eine Position ausdrückt, die nicht existieren kann. \%1cstimmt mit der Position in Spalte 1 überein und X\@<=fordert dazu auf, dass ein Zeichen Xdavor übereinstimmt. Vor der ersten Spalte darf jedoch kein Zeichen stehen. Selbst wenn Sie durch Xeinen Punkt (ein beliebiges Zeichen) ersetzen , \%1c.\@<=schlägt der reguläre Ausdruck dennoch fehl.
user938271
4

\zsgilt für den gesamten regulären Ausdruck und setzt das nächste Zeichen als erstes Zeichen der gesamten Übereinstimmung. Alles vor dem \zswird nicht als Teil des passenden Textes aufgenommen.

\@<=wirkt sich dagegen nur auf die Atome direkt um das Atom aus, sodass Sie festlegen können, dass das nächste Atom nur dann übereinstimmt, wenn es dem vorhergehenden Atom folgt. So zum Beispiel der reguläre Ausdruck:

\vbar.*(foo)@<=bar

Stimmt mit dem gesamten Text zwischen zwei Instanzen von bar(einschließlich der Instanzen selbst) überein , jedoch nur, wenn der zweiten vorangestellt wird foo. dh es wird übereinstimmen:

barbazfoobar

aber nicht:

barbazbazbar

Da \@<=dies auf diese Weise lokalisiert ist, können Sie es sogar \@<=mehrmals in einem einzelnen Ausdruck verwenden:

\vbar.*(foo)@<=bar.*(foo)@<=bar

Das Folgende stimmt mit drei Instanzen von überein bar, jedoch nur, wenn den zweiten beiden jeweils vorangestellt ist foo.

dh den Text gegeben:

barfoobarbazfoobar
barfoobarbazbazbar
barbazbarbazfoobar

Es wird nur mit der ersten Zeile übereinstimmen.

Reich
quelle
Aber Sie können den ersten Lookbehind mit austauschen \zs, dh dies sollte auch funktionieren : \vfoo\zsbar.*(foo)@<=bar.
Karl Yngve Lervåg
@ KarlYngveLervåg Guter Punkt. Ich habe bearbeitet, um die Unterscheidung klarer zu machen und um Beispiele zu verwenden, die \zsüberhaupt nicht ersetzt werden können.
Rich
Also, für mein Verständnis, \zsund \zekann mit Blick um regex Muster ersetzt werden, und sie sind stärker, nicht wahr? Stärker, weil sie mehrmals verwendet und gruppiert werden können \(\). Und auch, weil sie wie Perls Blick um Regex funktionieren. Irgendein Fehler?
Klaus
1
@klaus Das klingt für mich ungefähr richtig (obwohl ich kein Experte bin). Beachten Sie jedoch, dass Sie \zs/ verwenden sollten, \zewenn Sie können, da diese schneller sind als Umschauen.
Rich
Verstanden. Und \zsund \zesind offensichtlich intuitiver. Danke für die Erklärungen.
Klaus