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 nnoremap
voraus durch ein Leerzeichen oder ein Start-of-line (dh die Neue - Zeile von der vorhergehenden Zeile, damit die \_
vor der s
) und führte gn
Visual Mode einzugeben und visuell auswählen das nächste Spiel, aus irgendeinem Grunde nur die erste Spalte (dh Das erste n
in nnoremap
) wird ausgewählt - trotz der Tatsache, dass das gesamte nnoremap
Wort mit aktiviert markiert ist :hlsearch
.
Allerdings, wenn ich stattdessen die Suche starte
/\_s\@<=nnoremap
und dann versuchen gn
, das Ganze nnoremap
ist richtig ausgewählt. Was könnte hier los sein? Habe ich (wage ich zu sagen) einen obskuren Fehler entdeckt?
quelle
:h patterns
aber mein Gedächtnis legt nahe, dass Regexs aus Atomen bestehen, wenn dies hilft, den Unterschied zu erklären.Antworten:
Es sieht so aus, als hätten Sie tatsächlich einen obskuren Fehler gefunden. Ich habe das
gn
Textobjekt 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ßlich3) 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
wrapscan
bereits 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).
quelle
Christian hat sich vollständig mit der Frage des Buggy-Verhaltens von befasst
gn
, aber es gibt immer noch grundlegende Unterschiede zwischen\zs
und\@<=
. Das größte Wesen\@<=
modifiziert ein vorhergehendes Atom, während\zs
es ein Atom in sich selbst ist.Erwägen:
Regex 1 stimmt überein, da
\%1c
Spalte 1 übereinstimmt und dort ein X steht.\zs
bewirkt lediglich, dass die Übereinstimmung an einer Position nach dem X neu gestartet wird.Regex 2 stimmt jedoch nicht überein, da es zwar
\%1c
mit der ersten Spalte übereinstimmt,X\@<=
jedoch eine Breite von Null hat (wie in der Dokumentation erwähnt) undnnoremap
bei Spalte 2 beginnt. Es gibt nichts, was den Positionsunterschied zwischen den Spalten 1 und 2 ausgleichen könnte.Regex 3 stimmt überein, da
nnoremap
in Spalte 2 begonnen wird.quelle
nnoremap
aus 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.\%1c
stimmt mit der Position in Spalte 1 überein undX\@<=
fordert dazu auf, dass ein ZeichenX
davor übereinstimmt. Vor der ersten Spalte darf jedoch kein Zeichen stehen. Selbst wenn Sie durchX
einen Punkt (ein beliebiges Zeichen) ersetzen ,\%1c.\@<=
schlägt der reguläre Ausdruck dennoch fehl.\zs
gilt für den gesamten regulären Ausdruck und setzt das nächste Zeichen als erstes Zeichen der gesamten Übereinstimmung. Alles vor dem\zs
wird 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:Stimmt mit dem gesamten Text zwischen zwei Instanzen von
bar
(einschließlich der Instanzen selbst) überein , jedoch nur, wenn der zweiten vorangestellt wirdfoo
. dh es wird übereinstimmen:aber nicht:
Da
\@<=
dies auf diese Weise lokalisiert ist, können Sie es sogar\@<=
mehrmals in einem einzelnen Ausdruck verwenden:Das Folgende stimmt mit drei Instanzen von überein
bar
, jedoch nur, wenn den zweiten beiden jeweils vorangestellt istfoo
.dh den Text gegeben:
Es wird nur mit der ersten Zeile übereinstimmen.
quelle
\zs
, dh dies sollte auch funktionieren :\vfoo\zsbar.*(foo)@<=bar
.\zs
überhaupt nicht ersetzt werden können.\zs
und\ze
kann 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?\zs
/ verwenden sollten,\ze
wenn Sie können, da diese schneller sind als Umschauen.\zs
und\ze
sind offensichtlich intuitiver. Danke für die Erklärungen.