Je veux rechercher et remplacer chaque occurrence d'un certain modèle par un nombre décimal qui commence à 1
et augmente par un pour chaque correspondance.
Je peux trouver des questions formulées de manière similaire qui ne consistent pas à incrémenter un compteur mais à modifier chaque correspondance d'un montant fixe. D'autres questions similaires concernent l'insertion de numéros de ligne plutôt qu'un compteur d'incrémentation.
Exemple, avant:
#1
#1.25
#1.5
#2
Après:
#1
#2
#3
#4
Mes vraies données ont beaucoup plus de texte tout autour des choses que je veux renuméroter.
substitute
hippietrail
la source
la source
perldo
, vous pouvez utiliser:%perldo s/#\K\d+(\.\d+)?/++$i/ge
Réponses:
Vous avez besoin d'une substitution par un état. Je me souviens avoir fourni une (/ plusieurs?) Solution complète pour ce genre de problèmes sur SO.
Voici une autre façon de procéder (1). Maintenant, je vais procéder en 2 étapes:
Qui donne:
Si vous n'êtes pas habitué aux expressions rationnelles vim, j'utilise
:h /\zs
et\ze
pour spécifier le sous-motif que je fais correspondre, alors je fais correspondre une série de chiffres éventuellement suivie d'un point et d'autres chiffres. Ce n'est pas parfait pour n'importe quel nombre à virgule flottante, mais cela suffit ici.Remarque: vous devrez le conclure dans une fonction couple + commande pour une interface simple. Encore une fois, il y a des exemples sur SO / vim ( ici , ici , ici ) De nos jours, je connais assez de vim pour ne pas se soucier d'encapsuler cette astuce dans une commande. En effet je pourrai écrire cette commande du premier coup, tandis que je prendrai quelques minutes pour me souvenir du nom de la commande.
(1) L'objectif est de pouvoir maintenir un état entre les substitutions et de remplacer l'occurrence actuelle par quelque chose qui dépend de l'état actuel.
Merci à
:s\=
nous sommes en mesure d'insérer quelque chose résultant d'un calcul.Reste le problème de l'Etat. Soit nous définissons une fonction qui gère un état externe, soit nous mettons à jour nous-mêmes un état externe. En C (et dans les langages apparentés), nous aurions pu utiliser quelque chose comme
length++
oulength+=1
. Malheureusement, dans les scripts vim,+=
ne peut pas être utilisé hors de la boîte. Il doit être utilisé avec:set
ou avec:let
. Cela signifie que:let length+=1
incrémente un nombre, mais ne renvoie rien. Nous ne pouvons pas écrire:s/pattern/\=(length+=1)
. Nous avons besoin d'autre chose.Nous avons besoin de fonctions de mutation. c'est-à-dire des fonctions qui modifient leurs entrées. Nous avons
setreg()
,map()
,add()
et probablement plus. Commençons par eux.setreg()
mute un registre. Parfait. Nous pouvons écriresetreg('a',@a+1)
comme dans la solution de @Doktor OSwaldo. Et pourtant, cela ne suffit pas.setreg()
est plus une procédure qu'une fonction (pour ceux d'entre nous qui connaissent Pascal, Ada ...). Cela signifie qu'il ne retourne rien. En fait, cela retourne quelque chose. La sortie nominale (c'est -à- dire les sorties non exceptionnelles ) renvoie toujours quelque chose. Par défaut, lorsque nous avons oublié de renvoyer quelque chose, 0 est retourné - cela s'applique également aux fonctions intégrées. C'est pourquoi dans sa solution, l'expression de remplacement est en fait\=@a+setreg(...)
. Tricky, n'est-ce pas?map()
pourrait également être utilisé. Si nous partons d'une liste avec un seul 0 (:let single_length=[0]
), nous pourrions l'incrémenter grâce àmap(single_length, 'v:val + 1')
. Ensuite, nous devons renvoyer la nouvelle longueur. Contrairement àsetreg()
,map()
renvoie son entrée mutée. C'est parfait, la longueur est stockée à la première (et unique, et donc aussi la dernière) de la liste. L'expression de remplacement pourrait être\=map(...)[0]
.add()
est celui que j'utilise souvent par habitude (je l'ai juste réfléchimap()
et je n'ai pas encore évalué leurs performances respectives). L'idée avecadd()
est d'utiliser une liste comme état actuel et d'ajouter quelque chose à la fin avant chaque substitution. Je stocke souvent la nouvelle valeur à la fin de la liste et l'utilise pour le remplacement. Commeadd()
retourne aussi sa liste d'entrée mutées, nous pouvons utiliser:\=add(state, Func(state[-1], submatch(0)))[-1]
. Dans le cas d'OP, il suffit de se rappeler combien de correspondances ont été détectées jusqu'à présent. Il suffit de renvoyer la longueur de cette liste d'états. D'où mon\=len(add(state, whatever))
.la source
\=
qu'attend une expression, et parce que contrairement à C, cei+=1
n'est pas quelque chose qui incrémente et renvoie une expression. Cela signifie que derrière\=
j'ai besoin de quelque chose qui peut modifier un compteur et qui renvoie une expression (égale à ce compteur). Jusqu'à présent, les seules choses que j'ai trouvées sont les fonctions de manipulation de liste (et de dictionnaire). @Doktor OSwaldo a utilisé une autre fonction de mutation (setreg()
). la différence est quesetreg()
ne renvoie jamais rien, ce qui signifie qu'il renvoie toujours le nombre0
.Mais attention, cela écrasera votre registre
a
. Je pense que c'est un peu plus simple que la réponse de luc, mais peut-être que la sienne est plus rapide. Si cette solution est en quelque sorte pire que la sienne, j'aimerais entendre tout commentaire pourquoi sa réponse est meilleure. Tout commentaire pour améliorer la réponse sera très apprécié!(Il est également basé sur une réponse SO de la mienne /programming/43539251/how-to-replace-finding-words-with-the-different-in-each-occurrence-in-vi-vim -edi / 43539546 # 43539546 )
la source
@a+setreg('a',@a+1)
est plus court quelen(add(t,1))
. Sinon, c'est une autre astuce sale :). Je n'ai pas encore pensé à celui-ci. En ce qui concerne l'utilisation d'une fonction de mutation de dictionnaire dans le texte de remplacement, de:s
etsubstitute()
, j'ai remarqué que c'est beaucoup plus rapide que les boucles explicites - d'où l' implémentation de mes fonctions de liste dans lh-vim-lib . Je suppose que votre solution sera comparable à la mienne, peut-être un peu plus rapide, je ne sais pas.@a
inchangée. Dans les scripts, c'est important IMO. En mode interactif, en tant qu'utilisateur final, je saurai quel registre je peux utiliser. Jouer avec un registre est moins important. Dans ma solution, en mode interactif, une variable globale est gâchée; dans un script, ce serait une variable locale.+3
, je pourrais écrire quelque chose comme\=add(thelist, 3 + get(thelist, -1, 0))[-1]
.J'ai trouvé une question similaire mais différente que j'ai posée il y a quelques années et j'ai réussi à changer l'une de ses réponses sans bien comprendre ce que je faisais et cela fonctionne très bien:
Plus précisément, je ne comprends pas pourquoi la mienne n'utilise pas
%
ou pourquoi j'utilise simplement une variable simple que les autres réponses évitent pour une raison quelconque.la source
s//g
instruction normale . Quoi qu'il en soit, c'est une solution intéressante. Peut-être que @LucHermitte peut vous en dire plus sur les avantages et les inconvénients, car mes connaissances sur vimscript sont assez limitées par rapport aux siennes.printf()
- car les listes ont été introduites dans Vim 7. Mais je dois admettre que je ne m'attendais pas (/ je ne me souviens pas?) À<bar>
appartenir à la portée de:global
- IOW, le scénario auquel je m'attendais était d'appliquer le:sub
sur les lignes correspondantes, puis d'incrémenteri
une fois à la toute fin. Je m'attends à ce que cette solution soit légèrement plus lente. Mais est-ce que c'est vraiment important? L'important est la facilité avec laquelle nous pouvons trouver une solution de travail à partir de la mémoire + essais et erreurs. Par exemple, les Vimgolfers préfèrent les macros.g/s//
comportement de la portée permet d'autres astuces sales. Alors merci à vous deux pour les réponses intéressantes et la discussion, je n'apprends pas souvent grand-chose en donnant une réponse =).Il y a déjà trois bonnes réponses sur cette page, mais, comme l'a suggéré Luc Hermitte dans un commentaire , si vous faites cela au pied levé, l'important est la rapidité et la facilité avec laquelle vous pouvez trouver une solution de travail.
En tant que tel, c'est un problème que je n'utiliserais pas
:substitute
du tout: c'est un problème qui peut facilement être résolu en utilisant des commandes normales en mode normal et une macro récursive:(Si nécessaire) Tout d'abord, désactivez
'wrapscan'
. L'expression régulière que nous allons utiliser correspondra au texte de résultat souhaité ainsi qu'au texte initial, donc avec'wrapscan'
on, la macro continuerait sinon à être lue pour toujours. (Ou jusqu'à ce que vous réalisiez ce qui se passe et appuyez sur<C-C>
.):Configurez votre terme de recherche (en utilisant la même expression régulière de base déjà mentionnée dans les réponses existantes):
(Si nécessaire) Revenez au premier match en appuyant
N
autant de fois que nécessaire,(Si nécessaire) Remplacez la première correspondance par le texte souhaité:
Effacez le
"q
registre et commencez à enregistrer une macro:Tirez sur le compteur actuel:
Passez au match suivant:
Remplacez le compteur actuel par celui que nous venons de tirer:
Incrémentez le compteur:
Jouer la macro
q
. Le registre"q
est toujours vide car nous l'avons effacé à l'étape 5, donc rien ne se passe à ce stade:Arrêtez l'enregistrement de la macro:
Jouez la nouvelle macro et regardez!
Comme pour toutes les macros, cela ressemble à beaucoup d'étapes lorsque je l'explique comme je l'ai fait ci-dessus, mais notez qu'en fait, les saisir est très rapide pour moi: à part le récapitulatif-macro-enregistrement-passe-partout, ils ne sont que les habituels les commandes d'édition que j'exécute tout le temps pendant l'édition. La seule étape où j'ai dû faire quoi que ce soit même en approchant de la pensée était l'étape 2, où j'ai écrit l'expression régulière pour effectuer la recherche.
Formatée en deux commandes en mode ligne de commande et une série de frappes, la vitesse de ce type de solution devient plus claire: je peux évoquer les éléments suivants à peu près aussi vite que je peux taper 1 :
J'aurais probablement pu trouver les autres solutions sur cette page avec un peu de réflexion et un certain référencement de la documentation 2 , mais, une fois que vous comprenez le fonctionnement des macros, elles sont vraiment faciles à produire à la vitesse que vous modifiez habituellement.
1: Il y a des situations où les macros nécessitent plus de réflexion, mais je trouve qu'elles n'apparaissent pas beaucoup dans la pratique. Et généralement, les situations où elles se produisent sont celles où une macro est la seule solution pratique.
2: Cela ne veut pas dire que les autres répondeurs n'auraient pas pu trouver leurs solutions de la même manière: ils ont juste besoin de compétences / connaissances que je n'ai pas si facilement à portée de main. Mais tous les utilisateurs de Vim savent utiliser les commandes d'édition habituelles!
la source