Comment ajouter des numéros de ligne permanents à un fichier?

22

J'ai un fichier texte comme celui-ci (en utilisant gVim sous Windows)

foo bar baz quux 
corge grault garply 
waldo fred plugh 
[...150 more lines...]
xyzzy thud

Je veux ajouter un numéro à chaque ligne du fichier. Ne pas utiliser :set number, mais ajouter le numéro en tant que texte précédant chaque ligne, comme suit, de sorte que le numéro fasse partie du fichier.

1. foo bar baz quux 
2. corge grault garply 
3. waldo fred plugh 
[...~150 more lines...]
155. xyzzy thud
roblogic
la source
awkest probablement l'outil pour ce travail. Mais je suis sous Windows (soupir).
roblogic
Répondu ici déjà , tant
pis
1
Peut-être .. Ou est-ce plus général?
muru le
C'est similaire, mais je ne saurais pas quels sont les numéros de ligne permanents. Deuxièmement, l'autre question concerne toutes les lignes (et la réponse fait cela) pour gVim sous Windows en particulier et il s'agit d'une simple liste numérotée pour un paragraphe uniquement dans vim simple.
kenorb
3
Eh bien, je suppose que le post utilise "permanent" pour ne pas indiquer que le tampon doit être modifié et que les chiffres ne sont pas purement visuels (comme vous). La raison de la spécification de gvim sous Windows est d'éviter les utilitaires externes tels que catou nl, qui peuvent faire des lignes numériques, mais ne sont généralement pas disponibles sous Windows (comme OP l'indique dans leur commentaire awk). Les deux premières solutions sont purement Vim. Enfin, toutes les lignes par rapport à un para ne sont qu'une question de sélection de plage. Ce n'est clairement pas un gros problème.
muru

Réponses:

37

En pure mode Vim:

:%s/^/\=line('.').". "

Explication:

:%s/^/            " the substitution will be applied to the beginning of every line
\=                " the rest of the replacement part is an expression
line('.').". "    " the expression returns the current line number concatenated with a dot and a space

Voir :help \=et :help line().

L'utilisation d'une expression dans la pièce de rechange est très puissante et FWIW un assez bon point d'entrée pour vimscript.

romainl
la source
Comment puis-je ajouter cette commande très utile à une carte de touches dans vimrc?
cosmicraga
Pour accéder à la rubrique d'aide de vim pour la substitution::help sub-replace-expression
akurtser
9

Une bonne chose à propos des macros Vim est qu'elles peuvent récurrer (elles peuvent s'appeler):

  1. Effacer le registre q: qqq
  2. Ajoutez le numéro à la première ligne: ggI1.(n'oubliez pas l'espace!)
  3. Revenez au début de la ligne et commencez à enregistrer une macro: 0qq
  4. Copiez le numéro: yW
  5. Descendez d'une ligne et collez le nombre: +P
  6. Revenez au début de la ligne et incrémentez le nombre: 0<c-a>
  7. Revenez au début de la ligne (pour que la macro ne se casse pas lorsqu'elle arrive à doubler les chiffres!): 0
  8. Appelez une fois la macro pour la rendre récursive. À ce stade, il n'y a encore rien dans q registre, donc rien ne se passera: @q.
  9. Enregistrez la macro: q
  10. Appelez la macro une fois de plus et regardez les étincelles voler!: @@

La macro continuera ensuite à s'appeler jusqu'à ce qu'elle atteigne la fin du fichier.

Vous pouvez utiliser l'astuce macro récursive pour de nombreux autres problèmes similaires, c'est donc une bonne chose à savoir.

Si vous ne souhaitez pas utiliser une macro récursive pour une raison quelconque, vous pouvez omettre les étapes 1 et 8 et utiliser un décompte pour exécuter la macro plusieurs fois, par exemple 100@qexécutera la macro q100 fois.

Riches
la source
1
Puissant, je m'incline devant votre maîtrise. Les macros sont comme de la magie noire pour moi ...
roblogic
1
@ropata, une macro n'est qu'une séquence de commandes (principalement) en mode normal.
romainl
1
@romainl Je pense qu'il vaut mieux y voir une séquence de frappes .
Rich
2
@Rich, cela peut être une séquence de beaucoup de choses, y compris des commandes ex.
romainl
2
@romainl Oui, c'est pourquoi je pense qu'il vaut mieux y voir des frappes. Il reproduit exactement ce que vous tapez sur le clavier (y compris, comme vous le dites, les commandes ex), comme si vous l'aviez tout tapé manuellement.
Rich
7

J'aime utiliser la commande globale vim pour accomplir des tâches comme celle-ci. Cela s'applique à l'ajout d'une itération au début d'une ligne ou à la modification d'un symbole dans le texte. Cela semble plus compliqué que les autres solutions, mais c'est un modèle assez flexible à utiliser lorsque vous l'avez à portée de main, et il est facile à modifier sans beaucoup de réflexion.

Tout d'abord, choisissez votre plage (quelles lignes vous souhaitez appliquer). J'utilise généralement des marques (par exemple masur la première ligne et mbsur la seconde, mais vous pouvez également utiliser des numéros de ligne ou une sélection visuelle), puis entrez une modification de la commande suivante (actuellement modifiée pour votre cas d'utilisation)

:let i=1|'a,'bg/^/s/^/\=i.". "/|let i=i+1

Déconstruction

:let i=1

Cela définit une variable iavec une valeur de départ. Habituellement, les listes commencent par 1, donc je mets i à 1.

|

La barre démarre une nouvelle commande

'a,'b

Cela définit la plage de la commande suivante. Je vais de marque aen marque b, ce qui serait défini sur la première ligne et la dernière ligne de votre liste.

g/^/

Ceci est la commande globale. Il recherche dans le fichier (ou la plage) une expression régulière donnée et exécutera le reste de la ligne de commande sur chacune des lignes correspondantes. Je fais correspondre chaque ligne en recherchant "début de ligne". Si vous aviez du texte comme

Item some txt
other text

Item second item
whatever
Item third

et veulent seulement mettre ces étiquettes devant Itemet ignorer les autres lignes, faites g/Item/ou à la g/^Item/place (en supposant le texte littéral de l'article)

s/^/\=i.". "/

Cela exécute l'expression régulière pour remplacer le début de la ligne par la valeur de iconcaténé avec a .. En général, vous pouvez le faire pour n'importe quoi (remplacez l'étiquette Itempar le numéro, par exemple).

|let i=i+1

Même si la barre démarre une nouvelle commande, elle configure une deuxième commande à exécuter dans la commande globale, au lieu de la fin de la commande globale. Le résultat est que nous incrémentons iavant que la ligne suivante soit traitée par g. Voici un autre lieu de flexibilité. La modification de i peut être n'importe quoi (incrémenter de 2, appeler une fonction qui génère l'élément suivant de la séquence de Fibonacci, peu importe).

John O'M.
la source
7

Ajouter des numéros à toutes les lignes

Il est possible d'utiliser des commandes :%!nl -baou :%!cat -nqui ajouteront des numéros de ligne à toutes les lignes.

Sous Windows, vous devez avoir installé Cygwin / MSYS / SUA.

Ajouter des numéros aux lignes sélectionnées

Pour ajouter des numéros uniquement pour les lignes sélectionnées, veuillez les sélectionner en mode visuel ( vet curseurs), puis lorsque vous avez terminé - exécutez la commande: :%!nl(ignorer les lignes vides) ou :%!cat -n(lignes vides incluses).

Mise en page

Pour supprimer des espaces supplémentaires, sélectionnez-les dans le bloc visuel ( Ctrl+ v) et supprimez-les ( x).

Pour ajouter des caractères ( ., :, )) après les chiffres, les sélectionner dans le bloc visuel ( Ctrlde + v), puis ajoutez le caractère ( A, tapez le caractère, puis terminez avec Esc).

kenorb
la source
2
Cela ne donne pas le même formatage que celui indiqué dans la question. Cependant, j'aime la simplicité de la solution.
Karl Yngve Lervåg
@ KarlYngveLervåg Merci, inclus cela dans la réponse.
kenorb
5

Une modification de la réponse de romainl :

:%s/^\(\d\+\. \)\?/\=line('.').". "

Cela n'ajoutera pas seulement des numéros de ligne, il remplacera également les numéros de ligne existants s'ils sont déjà là. Si vous avez inséré une ligne à mi-chemin, elle renumérotera tout comme prévu.

Cela fonctionne en remplaçant n'importe quel nombre suivi d'un. et un espace au début de la ligne avec un nouveau numéro. Cela cassera évidemment si vous avez une ligne qui commence déjà par ce modèle, alors utilisez-la avec réflexion.

La partie ajoutée:

  • ^ - Début de ligne
  • \( - Démarrer un nouveau sous-groupe
  • \d\+ - Faites correspondre un chiffre une ou plusieurs fois
  • \. - Faites correspondre un point ( .) et un espace .
  • \) - Fin du sous-groupe
  • \? - Rendez le groupe facultatif, pour qu'il fonctionne comme avant s'il n'y a pas encore de numéro sur cette ligne.

Astuce bonus:
pour supprimer les numéros de ligne, vous pouvez utiliser le même modèle avec la partie de remplacement vide:

:%s/^\(\d\+\. \)\?//
Martin Tournoij
la source
5
I1. <esc>^qqyWjP^<C-a>q

Cela numérote les deux premières lignes et vous pouvez appuyer sur @qpour numéroter les lignes suivantes (ou tapez ex. 18@qSi vous voulez numéroter 20 lignes au total).

Explication:

I1. <esc>  Number the first line
hqq        Go back to the start of the line and start recording a macro
yWjP       Copy the line number to the next line
^<C-a>     Increment the next line's line number
q          Finish recording

L'avantage de ceci est qu'il ne nécessite aucune commande externe, ce qui est utile si vous travaillez avec Vim sous Windows, par exemple.

Poignée de porte
la source
Après avoir tapé, 1. <esc>hvous êtes sur la deuxième colonne, pas sur la première colonne. Je remplacerais le hpar 0, après quoi je pense que votre solution devrait être très bonne.
Karl Yngve Lervåg
@ KarlYngveLervåg Oups, c'était une faute de frappe. Merci, corrigé.
Poignée de porte
Aucun problème. Cependant, vous n'avez toujours pas mis à jour l'explication. Aussi: Sur de nombreux claviers, ^attend un deuxième caractère afin de permettre des combinaisons de frappe comme ^a -> â. Je suis toujours d'accord pour dire que c'est la meilleure solution, mais je pense que cela devrait également être mentionné.
Karl Yngve Lervåg
3

Je pense que la réponse choisie est la meilleure, mais dans l'esprit de la variété, je proposerai une alternative en utilisant un programme externe:

:%!cat -n

Cela filtrera l'intégralité de votre tampon (comme indiqué par %) via le programme externe cat, où l' -nindicateur ajoute à chaque ligne d'entrée un numéro de ligne.

Cela, bien sûr, nécessite que vous ayez catinstallé, ce qui est vrai pour (probablement) tous les systèmes de type Unix.

Consultez :help :range!pour plus de détails sur le filtrage via des programmes externes.

tommcdo
la source
1
Je me rends compte que le demandeur utilise gVim sur Windows, donc cette solution ne fonctionnera probablement pas là-bas. Cependant, je pense que cela donne encore l'occasion à d'autres d'en tirer des leçons.
tommcdo
Si vous avez installé msysgitet ajouté cela à votre PATH (IIRC c'est une option d'installation), cette solution devrait également fonctionner sous Windows.
Martin Tournoij
4
cat -nn'est pas POSIX, mais l' nlest, donc ce pourrait être une meilleure option.
muru
2

Une solution un peu hackish pourrait être la suivante (tout ce qui est écrit entre <et> doit être inséré après avoir appuyé sur Ctrl+ v):

:%normal :redir @"<Enter>:-=<Enter>:redir END<Enter>I<C-R>".<Tab><Esc>kdd

Déconstruction

:%normal {commands}

exécute la commande en mode normal sur chaque ligne spécifiée par la plage, dans ce cas, chaque ligne

:redir @"

redirige chaque sortie effectuée par les commandes ex vers le tampon sans nom.

:.=

est une commande ex qui affiche le numéro de ligne actuel (avec un saut de ligne précédent malheureusement)

:redir END

arrête la redirection vers le tampon sans nom

I<C-R>".<Tab><Esc>

insère le contenu du tampon sans nom avec un. et un onglet à l'avant de chaque ligne et quitte le mode d'insertion.

kdd

monte d'une ligne et supprime la nouvelle ligne qui est le résultat de la commande:. =.

FloriOn
la source