Voici ce que j'obtiens de la documentation: \zs
"démarre la partie en surbrillance" après avoir trouvé l'expression rationnelle précédente, et \@<=
"démarre la partie en surbrillance" après avoir trouvé l' atome précédent . Mais je ne comprends pas exactement les subtilités de cela, alors quelqu'un peut-il expliquer en quoi elles diffèrent un peu plus en profondeur?
C'est ce qui m'a rendu curieux: si je cours
/\_s\zsnnoremap
c'est-à-dire sélectionner nnoremap
précédé d'un espace ou d'un début de ligne (c'est-à-dire la nouvelle ligne de la ligne précédente, donc la \_
précédente de la s
), puis exécuter gn
pour passer en mode visuel et sélectionner visuellement la correspondance suivante, pour une raison quelconque, uniquement la première colonne (c'est-à-dire le premier n
dans nnoremap
) est sélectionné - malgré le fait que le nnoremap
mot entier est mis en surbrillance avec :hlsearch
activé.
Cependant, si je lance plutôt la recherche
/\_s\@<=nnoremap
puis essayez gn
, l'ensemble nnoremap
est correctement sélectionné. Que pourrait-il se passer ici? Ai-je (oserais-je dire) découvrir un bug obscur?
la source
:h patterns
que c'est dedans mais ma mémoire suggère que les regex sont composées d'atomes, si cela aide à expliquer la différence.Réponses:
Il semble que vous ayez en effet trouvé un bug obscur. J'ai implémenté le
gn
textobject en 2012 pour quelque chose de Vim 7.3. Cela fonctionne essentiellement de la manière suivante:1) Il recherche en arrière la dernière correspondance de l'expression régulière actuelle.
2) Il recherche la correspondance suivante de l'expression régulière en cours.
Cela devrait indiquer clairement que le curseur sera au début du match suivant, même s'il était déjà là au début de 1).
finalement3) il recherche la fin de l'expression régulière courante. et y place le curseur.Maintenant, ce qui se passe ici, c'est que la recherche de la fin de la correspondance actuelle se termine et revient à la fin de la correspondance précédente (car elle
wrapscan
est déjà définie, après avoir été désactivée pour 1)). Il place ensuite le marqueur visuel sur la zone depuis le début (fin du point 2) et la zone vers laquelle se trouve l'élément de recherche suivant 3).J'examinerai de plus près le problème et soumettrai probablement un correctif pour Vim plus tard.
[Mise à jour 22.05.2018] J'ai écrit et soumis un correctif pour corriger ce problème.
[Update2 22.05.2018] Et le correctif a été fusionné en tant que niveau de correctif 8.1.0018
[Mise à jour 22.10.2019] Depuis le patch 8.1.629 de Vim, la troisième étape n'est plus exécutée. Au lieu de cela, Vim peut maintenant déterminer la fin du match lorsqu'il trouve le début du match (étape 2)
la source
Christian a complètement abordé la question du comportement en buggy de
gn
, mais il existe encore des différences fondamentales entre\zs
et\@<=
. Le plus grand être\@<=
modifie un atome précédent, tandis\zs
qu'un est un atome en soi.Considérer:
Regex 1 correspond, car
\%1c
correspond à la colonne 1 et il y a un X là.\zs
fait simplement redémarrer le match à une position après le X.Regex 2 ne correspond cependant pas, car bien qu'il
\%1c
corresponde à la première colonne, il aX\@<=
une largeur nulle (comme mentionné dans la documentation) etnnoremap
commence à la colonne 2. Il n'y a rien pour compenser la différence de position entre les colonnes 1 et 2.Regex 3 correspond depuis le
nnoremap
début à la colonne 2.la source
nnoremap
de l'expression régulière produirait une correspondance; mais le regex échoue toujours même sans. Je pense qu'il échoue car\%1cX\@<=
exprime une position qui ne peut exister.\%1c
correspond à la position de la colonne 1 etX\@<=
demande qu'un caractèreX
corresponde avant cela. Mais il ne peut y avoir aucun caractère avant la première colonne. C'est pourquoi, même si vous le remplacezX
par un point (n'importe quel caractère), l'expression régulière\%1c.\@<=
échoue toujours.\zs
s'applique à l'expression régulière entière et définit le caractère suivant comme le premier caractère de la correspondance entière. Tout ce qui précède\zs
ne sera pas inclus dans le texte correspondant.\@<=
, d'autre part, n'affecte que les atomes directement autour de lui, ce qui vous permet de spécifier que l'atome suivant ne correspondra que s'il suit l'atome précédent. Ainsi, par exemple, l'expression régulière:Correspondra à tout le texte entre deux instances de
bar
(y compris les instances elles-mêmes), mais uniquement si la seconde est précédée defoo
. c'est-à-dire qu'il correspondra à:mais non:
Parce qu'il
\@<=
est localisé de cette manière, vous pouvez même l'utiliser\@<=
plusieurs fois dans une seule expression:Ce qui suit correspondra à trois instances de
bar
, mais uniquement si les deux secondes sont chacune précédées defoo
.c'est-à-dire compte tenu du texte:
Il correspondra uniquement à la première ligne.
la source
\zs
, à savoir, cela devrait aussi fonctionner:\vfoo\zsbar.*(foo)@<=bar
.\zs
ils ne peuvent pas être substitués du tout.\zs
et\ze
peut être remplacé par un regard autour des modèles d'expression régulière, et ils sont plus puissants, non? Plus puissant car ils peuvent être utilisés plus d'une fois et peuvent être regroupés\(\)
. Et aussi parce qu'ils fonctionnent comme l'apparence de perl autour des regex. Vous vous trompez?\zs
/\ze
quand vous le pouvez, car ils sont plus rapides que les regards croisés.\zs
et\ze
sont évidemment plus intuitifs. Merci pour les explications.