Comment copier chaque ligne 11 fois, en incrémentant le dernier «1» de chaque ligne de 2 à 12

9

J'ai un certain nombre de lignes dans un fichier, et je voudrais copier chaque ligne 11 fois (en transformant chaque ligne en 12 lignes), et incrémenter le dernier "1" de chaque ligne afin que les 12 lignes aient "1" à " 12 ", où se trouvait initialement le" 1 ". Il peut y avoir d'autres occurrences de «1» dans chaque ligne, mais le «1» que je veux incrémenter sera toujours la dernière occurrence de chaque ligne. Une autre façon de voir les choses est que le dernier "1" est toujours après "/ nt /" - comme dans "/ nt / 1" (et ce sera toujours la seule occurrence de "/ nt / 1" dans chaque ligne) .

Ainsi, par exemple, si j'ai:

1stlineblahblahblah/nt/1blah
2ndlineblahblahblah/nt/1blah
3rdlineblahblahblah/nt/1blah

Je veux en faire:

1stlineblahblahblah/nt/1blah
1stlineblahblahblah/nt/2blah
1stlineblahblahblah/nt/3blah
1stlineblahblahblah/nt/4blah
1stlineblahblahblah/nt/5blah
1stlineblahblahblah/nt/6blah
1stlineblahblahblah/nt/7blah
1stlineblahblahblah/nt/8blah
1stlineblahblahblah/nt/9blah
1stlineblahblahblah/nt/10blah
1stlineblahblahblah/nt/11blah
1stlineblahblahblah/nt/12blah
2ndlineblahblahblah/nt/1blah
2ndlineblahblahblah/nt/2blah
2ndlineblahblahblah/nt/3blah
...

J'avais précédemment trouvé la commande:

:for i in range(0,12) | put ='1stlineblahblahblah/nt/'.i.'blah' | endfor

fonctionne à cet effet, mais je devrais exécuter manuellement cette commande pour chaque ligne et taper chaque ligne (ou la copier-coller) moi-même. Existe-t-il un moyen de prendre les lignes qui sont déjà dans le fichier et d'exécuter simplement une commande qui transforme chaque ligne en douze, de la manière que j'ai décrite?

Merci d'avance à tous ceux qui peuvent m'aider. Je tenais également à souligner qu'il s'agit de ma deuxième question ici, et j'étais heureux d'avoir obtenu plusieurs solutions rapides et efficaces à ma première question, pour lesquelles j'étais très reconnaissant.

ablewasiereisawelba
la source

Réponses:

8

Voici une substitution qui résout le problème:

:%s/\(.*\)1\(.*\)/\=join(map(range(1, 12), 'submatch(1) . v:val . submatch(2)'), "\n")

La substitution correspond à chaque ligne qui contient "1" et capture le texte avant {c1}et après {c2}le dernier "1". Pour chaque ligne correspondante, la plage de nombres de un à douze {n}est mappée pour créer douze lignes du formulaire {c1}{n}{c2}. Chaque groupe de douze lignes remplace sa ligne associée d'origine.

Tu vois :h sub-replace-expression.

djjcast
la source
2
Wow, super commande sur une seule ligne. Je me souviens que vous avez également trouvé une solution élégante en ligne pour la première question que j'ai posée il y a quelques semaines. Très bon travail. Merci beaucoup. En outre, je suppose qu'il existe un moyen de mettre cela dans le fichier _vimrc afin que je puisse exécuter une commande ou une fonction facile à mémoriser sans taper la ligne entière ci-dessus (ou avoir à faire défiler la liste des commandes précédentes), mais Je ne connais pas encore assez bien la syntaxe _vimrc pour savoir comment le faire.
ablewasiereisawelba
10

Vous pouvez le faire en

  1. enregistrer une macro, puis
  2. en utilisant la globalcommande ex pour exécuter la macro n nombre de fois pour chaque ligne du fichier.

Après avoir enregistré la macro, annulez les modifications effectuées pendant l'enregistrement, sinon il y aura n + 1 lignes supplémentaires pour la première ligne et n pour les lignes consécutives.

Enregistrez la macro dans le aregistre avec

qayyp$?\d<CR><C-A>q

Cela enregistre dans register a( qa...q) la commande suivante:

  • yyp: dupliquer la ligne courante
  • $: passer à la fin de la ligne
  • ?\d<CR>: recherche en arrière d'un seul chiffre
  • <C-A>: incrémente le chiffre sous le curseur de un

Lorsque la macro est enregistrée, supprimez les modifications apportées lors de son enregistrement en annulant ( uu) ou en supprimant la ligne actuelle ( dd). Répétez ensuite la macro 11(ou n'importe quel nombre de fois) pour chaque ligne du fichier avec la commande globale:

:g//normal 11@a
jjaderberg
la source
2
Ça a marché! Très bien merci. J'ai eu un problème au départ avec le Ctrl-a mettant tout en surbrillance au lieu d'ajouter, car j'utilise gVim dans Windows ... mais j'ai fait une recherche rapide et j'ai trouvé ce fil - stackoverflow.com/questions/289681/… - où je utilisé la suggestion de mettre nnoremap <kPlus> <Ca> nnoremap <kMinus> <Cx> dans le _vimrc afin que je puisse utiliser les touches "+" et "-" pour ajouter et soustraire. De plus, la commande globale devait être: g // normal 11 @ a pour moi, mais cela a été facilement compris. Je vous remercie!
ablewasiereisawelba
6

Deux façons:

Utilisez une macro!

Commençant par

1stlineblahblahblah/nt/1blah
2ndlineblahblahblah/nt/1blah
3rdlineblahblahblah/nt/1blah

Avec votre curseur sur la première ligne

qqyyp$?\d<CR><Ctrl-a>q
10@q

Qui fait:

qq Commencer à enregistrer une macro dans le registre q

yyp tirez sur la ligne actuelle et collez-la ci-dessous

$?\d<CR> Allez à la fin de la ligne et trouvez le premier chiffre en regardant en arrière

<Ctrl-a> Augmentez le nombre

q Arrêtez l'enregistrement de la macro.

Cela vous laisse avec:

1stlineblahblahblah/nt/1blah
1stlineblahblahblah/nt/2blah
2ndlineblahblahblah/nt/2blah
2ndlineblahblahblah/nt/3blah

Avec le curseur sur la deuxième ligne. Répétez simplement cette macro autant de fois que vous le souhaitez (par exemple, répétez-la dix fois avec 10 @ q). Si vous souhaitez automatiser ce processus pour chaque ligne, exécutez-le globalement sur chaque ligne:

:g//normal 11@q

Alternativement, avec une version plus récente de vim: collez la ligne de votre choix autant de fois, bloc visuel sélectionnez le chiffre que vous souhaitez incrémenter et appuyez sur g <Ctrl-a>. Cela devrait incrémenter tous les nombres du bloc visuel comme vous le souhaitez. Il s'agit cependant d'un processus plus manuel.

fruglemonkey
la source
1
Génial, je ne connaissais pas le g <c-a>chemin. Merci d'avoir partagé.
kba se tient avec Monica le
1
@fruglemonkey La première partie de votre réponse est la même que celle ci-dessus, mais merci quand même. La deuxième partie, je ne pense pas que cela fonctionne pour moi (sauf si je fais quelque chose de mal), donc je ne dois pas utiliser la bonne version.
ablewasiereisawelba
5

Je trouve plus facile d'utiliser des macros pour des tâches ponctuelles comme celle-ci. Commencez simplement à enregistrer une macro avec q+ nom du registre et effectuez la tâche une fois. Je vois une tâche reproductible ici:

  • Sélectionnez la ligne
  • coup sec
  • coller (vous mettra dans la ligne suivante)
  • aller en fin de ligne
  • revenir en arrière un mot
  • incrémenter d'un

Enregistrez maintenant les frappes nécessaires pour vous inscrire a, en mode normal:

qayyp$b<c-a>.

Supprimez à nouveau la ligne pour tester si l'exécution de la macro 11 fois donne le bon résultat pour une ligne:

11@a

Cela fait! Permet donc d'annuler à nouveau et d'automatiser l'ensemble du processus dans une deuxième macro b:

qb11@aj

Vous pouvez maintenant exécuter @bjusqu'à la fin du fichier et cela devrait produire la sortie que vous souhaitez. Cela semble compliqué, mais ce n'est vraiment pas une fois que vous êtes habitué aux modèles d'édition typiques.

kba est aux côtés de Monica
la source
Je ne sais pas si je fais quelque chose de mal, mais cela ne semble pas fonctionner. J'ai suivi ce que vous avez écrit, mais j'ai peut-être mal compris quelque chose ou n'ai pas exécuté correctement quelque chose. (J'obtiens le premier numéro de la ligne incrémenté, pas le dernier numéro de la ligne.) Merci d'avoir répondu.
ablewasiereisawelba
3
Je pense que la première macro devrait l'être qaVyp$b<c-a>. Ou mieux, juste qayyp$b<c-a>.
Karl Yngve Lervåg
1
Merci, @ KarlYngveLervåg, vous avez raison, j'ai corrigé la macro.
kba se tient avec Monica le
2
Argh :( merci d'être minutieux @ablewasiereisawelba. Je suppose que la macro qqyyp$?\d<CR><Ctrl-a>qde @fruglemonkey et @jjaderberg est meilleure car elle recherche le dernier numéro. Je le changerai pour être complet.
kba se tient avec Monica le
2
@kba Je pensais juste que si quelqu'un prenait le temps et l'effort de répondre à ma question, je pouvais au moins essayer sa solution - même si j'avais déjà trouvé une solution de travail de quelqu'un d'autre. J'apprécie vos efforts - et si cela vous fait vous sentir mieux, vous avez toujours des kilomètres d'avance sur moi. :)
ablewasiereisawelba
2

Enregistrez la macro suivante et utilisez-la pour chaque ligne:

qqyy11p/\/\zs1<CR><C-v>10jg<C-a>q

La principale différence par rapport aux autres réponses est que cela fait appel g<C-a>à une sélection de colonnes qui incrémente chaque ligne avec un numéro différent. Vérifiez :help v_g_CTRL-Apour plus d'informations. J'ai également utilisé \zspour sélectionner la position de départ du motif, de sorte que le curseur s'arrête au numéro après la recherche.

Veuillez noter que vous avez besoin d'une version récente de Vim pour que cela fonctionne.

Vitor
la source
1
@fruglemonkey l'a également proposé . C'est une fonctionnalité intéressante, bien qu'elle soit assez récente (selon les normes Vim), depuis la 7.4.754 qui n'a pas encore été livrée à toutes les distributions.
kba se tient avec Monica le
Vitor
1
@Vitor Je n'ai que gVim 7.4, donc je ne pense pas pouvoir faire le g<C-a>@fruglemonkey auquel vous avez fait référence, mais merci d'avoir répondu. Je dois noter que lorsque vous essayez votre macro - juste avant d'arriver à la g<C-a>partie, ce n'est pas le dernier caractère "1" que je cherche à incrémenter qui est mis en surbrillance, mais c'est plutôt le caractère avant le premier "1" "caractère mis en surbrillance. (En outre, je pense que cela aurait dû être yy11pet 10jdans la macro, car je cherche à ajouter 11 lignes - pour un total de 12.)
ablewasiereisawelba
1
Merci pour vos commentaires. J'ai mis à jour la réponse en conséquence. Décidé d'utiliser \zs, mais j'aurais tout aussi bien pu ajouter un laprès <CR>.
Vitor
1
Vous avez probablement des paramètres dans votre vimrc qui affectent la recherche d'expressions régulières. Essayez à nouveau en démarrant Vim avec vim -u NONE. Je viens de le faire et cela fonctionne parfaitement! En fait, il n'y a aucun moyen que la recherche corresponde au premier 1 car elle nécessite une barre oblique précédente.
Vitor