Oto, co otrzymuję z dokumentacji: \zs
„rozpoczyna podświetloną część” po dopasowaniu poprzedniego wyrażenia regularnego, i \@<=
„rozpoczyna podświetloną część” po dopasowaniu poprzedniego atomu . Ale nie do końca rozumiem subtelności tego, więc czy ktokolwiek może wyjaśnić, czym różnią się nieco bardziej dogłębnie?
Właśnie to mnie zainteresowało: jeśli biegnę
/\_s\zsnnoremap
tzn. wybierz nnoremap
poprzedzony spacją lub początkiem linii (tj. nowa linia z poprzedniej linii, stąd \_
poprzednia s
), a następnie uruchom, gn
aby przejść do trybu wizualnego i wizualnie wybierz następne dopasowanie, z jakiegoś powodu tylko pierwszą kolumnę (tj. pierwsze n
w nnoremap
) jest zaznaczone - pomimo tego, że całe nnoremap
słowo jest podświetlone z :hlsearch
włączonym.
Jeśli jednak zamiast tego uruchomię wyszukiwanie
/\_s\@<=nnoremap
a następnie spróbuj gn
, całość nnoremap
jest odpowiednio wybrana. Co tu się dzieje? Czy (śmiem powiedzieć) odkryłem jakiś niejasny błąd?
źródło
:h patterns
ale moja pamięć sugeruje, że wyrażenia regularne składają się z atomów, jeśli to pomaga wyjaśnić różnicę.Odpowiedzi:
Wygląda na to, że rzeczywiście znalazłeś niejasny błąd. Zaimplementowałem
gn
textobject już w 2012 roku dla Vima 7.3. Zasadniczo działa w następujący sposób:1) Wyszukuje do tyłu ostatnie dopasowanie bieżącego wyrażenia regularnego.
2) Szuka do przodu następnego dopasowania bieżącego wyrażenia regularnego.
Powinno to wyjaśnić, że kursor będzie na początku następnego meczu, nawet jeśli był tam już na początku 1).
Wreszcie3) szuka końca bieżącego wyrażenia regularnego. i umieszcza tam kursor.To, co się tutaj dzieje, polega na tym, że wyszukiwanie końca bieżącego dopasowania jest zawijane i przechodzi z powrotem na koniec poprzedniego dopasowania (ponieważ
wrapscan
jest już ustawione, po wyłączeniu na 1). Następnie ustawia znacznik wizualny na obszar od początku (koniec punktu 2) i obszar przesunięty do następnego elementu wyszukiwania 3).Przyjrzę się bliżej problemowi i prawdopodobnie prześlę łatkę dla Vima później.
[Aktualizacja 22.05.2018] Napisałem i przesłałem łatkę, aby naprawić to zachowanie.
[Aktualizacja2 22.05.2018] A łatka została scalona jako łatka na poziomie 8.1.0018
[Aktualizacja 22.10.2019] Od poprawki Vima 8.1.629 trzeci krok nie jest już wykonywany. Zamiast tego Vim może teraz określić koniec meczu, znajdując początek meczu (krok 2)
źródło
Christian całkowicie zajął się kwestią zachowania błędnego
gn
, ale nadal istnieją fundamentalne różnice między\zs
i\@<=
. Największa istota\@<=
modyfikuje poprzedni atom, podczas gdy\zs
sama jest atomem.Rozważać:
Regeks 1 pasuje, ponieważ
\%1c
pasuje do kolumny 1 i tam jest X.\zs
powoduje jedynie, że dopasowanie zostanie wznowione w miejscu po X.Regeks 2 jednak nie pasuje, ponieważ chociaż
\%1c
pasuje do pierwszej kolumny,X\@<=
ma zerową szerokość (jak wspomniano w dokumentacji) innoremap
zaczyna się od kolumny 2. Nic nie może nadrobić różnicy pozycji między kolumnami 1 i 2.Regex 3 pasuje od początku
nnoremap
w kolumnie 2.źródło
nnoremap
z wyrażenia regularnego spowodowałoby dopasowanie; ale wyrażenie regularne nadal nie działa nawet bez. Myślę, że to się nie udaje, ponieważ\%1cX\@<=
wyraża pozycję, która nie może istnieć.\%1c
dopasowuje pozycję w kolumnie 1 iX\@<=
prosi oX
dopasowanie znaku przed tym. Ale przed pierwszą kolumną nie może być żadnego znaku. Dlatego nawet jeśli zamieniszX
kropkę (dowolny znak), wyrażenie regularne\%1c.\@<=
nadal zawiedzie.\zs
dotyczy całego wyrażenia regularnego i ustawia następny znak jako pierwszy znak całego dopasowania. Coś wcześniejszego\zs
nie będzie uwzględnione jako część pasującego tekstu.\@<=
, z drugiej strony, wpływa tylko na atomy bezpośrednio wokół niego, co pozwala określić, że następny atom będzie pasował tylko wtedy, gdy będzie następował po atomie poprzedzającym. Na przykład wyrażenie regularne:Dopasuje cały tekst między dwoma wystąpieniami
bar
(w tym same wystąpienia), ale tylko wtedy, gdy drugi będzie poprzedzony znakiemfoo
. tzn. będzie pasować:ale nie:
Ponieważ
\@<=
jest on zlokalizowany w ten sposób, możesz nawet użyć\@<=
wiele razy w jednym wyrażeniu:Poniższe będzie pasowało do trzech wystąpień
bar
, ale tylko wtedy, gdy każde z dwóch poprzedzonych będzie znakiemfoo
.tzn. biorąc pod uwagę tekst:
Będzie pasować tylko do pierwszej linii.
źródło
\zs
, czyli ta powinna także działać:\vfoo\zsbar.*(foo)@<=bar
.\zs
ogóle nie można zastąpić.\zs
i\ze
można je zastąpić rozejrzeniem się po wzorach wyrażeń regularnych, a są one bardziej wydajne, prawda? Potężniejsze, ponieważ mogą być używane więcej niż jeden raz i mogą być grupowane\(\)
. A także dlatego, że działają jak Perl rozglądają się po wyrażeniu regularnym. Coś się myliło?\zs
/\ze
kiedy możesz, ponieważ są one szybsze niż rozglądanie się.\zs
i\ze
są oczywiście bardziej intuicyjne. Dziękuję za wyjaśnienia.