Numéroter les lignes d'un texte pour une relecture à plusieurs
Publié le 12/08/2026 · 17 min de lecture · Outils texte & langage
Daniel Okonkwo — Développeur front-end et rédacteur Tech chez Allin
Performance web · Formats de fichiers
Vérifié à partir de 3 sources
Colle ton texte dans add-line-numbers et chaque ligne reçoit un numéro devant, à partir de 1. Le champ « Commencer à » accepte une autre valeur, mais pas zéro : le code lit Number(start) || 1, et 0 est falsy, donc 0 revient à 1. Les départs négatifs fonctionnent : mets −3 sur trois lignes et tu obtiens −3, −2, −1. L'alignement est automatique et se fait avec des espaces, jamais avec des zéros : la largeur vient du dernier numéro, donc 102 lignes donnent « 1. » jusqu'à « 102. », et un texte de 99 lignes donne « 1. » avec un seul espace. Le séparateur par défaut est un point suivi d'une espace ; dix autres sont proposés, dont « 1) », « 1: », « [1] », « #1 » et une tabulation. Le retour est asymétrique, mais il n'est plus destructeur. remove-line-numbers ne connaît qu'un motif — espaces de tête, chiffres, un séparateur pris dans un jeu de huit, puis une seule espace ou la fin de la ligne — il annule donc huit des onze et laisse volontairement le tiret, la barre verticale et l'espace simple en place : « 10 - 20 people » et « 1 | Alice | 30 » sont bien plus souvent du contenu que de la numérotation. Comme il ne prend plus qu'une seule espace au lieu d'une suite gourmande, numéroter du JavaScript indenté puis le dénuméroter rend le code octet pour octet, indentation comprise. Et comme un séparateur doit être suivi d'une espace, « 3.14 is pi » et « 12.50 Coffee » restent où ils sont. Ce qu'aucune règle ne peut sauver, c'est une ligne qui ressemble exactement à la sortie de l'outil : « 2026. A year. » revient toujours en « A year. » Numérote une copie, garde l'original.
La numérotation commence à 1 et ne peut pas être mise à 0, l'alignement se fait avec des espaces et non des zéros, et l'outil de suppression annule huit des onze séparateurs sans toucher à l'indentation. Ce qu'il ne sait toujours pas faire, c'est distinguer tes numéros des siens.
Pourquoi un texte partagé a besoin de numéros
Le code arrive avec ses numéros. L'éditeur les affiche dans la marge gauche, un diff les imprime de part et d'autre de la modification, et un commentaire de revue sur une plateforme d'hébergement s'accroche à l'un d'eux. La prose, non. Une clause de contrat, un jeu de sous-titres, un export de mémoire de traduction, une liste de noms de produits à vérifier par deux collègues : aucun de ces textes ne dispose d'une manière stable de dire « le quatrième en partant du haut », sinon en comptant.
C'est le comptage manuel qui fait dérailler la relecture. Deux personnes comptent depuis des endroits différents, l'une inclut la ligne vide et l'autre non, et une heure plus tard il y a deux corrections sur la même clause et une sur une clause que personne ne voulait toucher. Attacher un numéro à chaque ligne avant de faire circuler le texte supprime toute cette famille de malentendus pour le prix d'un collage.
Le mot important est « avant ». Les numéros sont un système de coordonnées, et un système de coordonnées ne sert que tant qu'il ne bouge pas. Si quelqu'un renumérote un texte déjà annoté, chaque commentaire devient une devinette. Numérote une fois, fais circuler exactement cette version, et récolte les corrections par rapport à elle.
Ce que l'outil produit réellement
Le réglage par défaut est un point suivi d'une espace : « first line » devient « 1. first line ». Dix autres séparateurs sont proposés : « 1) », « 1: », « 1 - », « 1 | », « [1] », « 1] », « #1 », « 1 → », une simple espace et une tabulation. Deux d'entre eux entourent le numéro au lieu de le suivre, d'où l'allure différente de « [1] » et « #1 ».
L'alignement est calculé à partir du dernier numéro et appliqué avec des espaces ordinaires, pas des zéros. Un texte de 102 lignes revient avec « 1. line1 » en tête et « 102. line102 » en bas, les chiffres alignés à droite. La largeur est décidée une fois pour toutes, avant la première ligne : un texte de 99 lignes a une largeur de deux, un texte de 100 lignes une largeur de trois — une espace de plus sur chaque ligne, à cause d'une seule ligne ajoutée. Si tu compares deux versions numérotées, c'est la raison pour laquelle toutes les lignes apparaissent comme modifiées.
Trois petits comportements méritent d'être connus avant de coller quelque chose de long. Un saut de ligne final produit une ligne vide numérotée à la fin, parce que découper « a\nb\n » sur les sauts de ligne donne trois morceaux dont le troisième est vide — la sortie se termine par « 3. ». Une entrée vide produit « 1. » et non rien du tout. Et une entrée avec des fins de ligne Windows revient avec des fins de ligne Unix : le découpage accepte un retour chariot avant le saut de ligne, mais le recollage ne remet que le saut de ligne.
Commencer à 1, et seulement à 1 — ou à un nombre négatif
Le champ « Commencer à » existe parce qu'un extrait numéroté vient généralement de quelque part : la page quatre d'une transcription ne devrait pas recommencer à 1. Mets-le à 500 et la sortie donne 500, 501, 502, avec une largeur de trois. Jusque-là, tout fonctionne comme annoncé.
Zéro fait exception, et ce n'est pas un défaut qu'on contourne en le tapant autrement. La valeur est lue comme Number(start) || 1. Zéro fait partie des valeurs falsy de JavaScript : l'expression retombe donc sur 1 — taper 0 et ne rien taper donnent le même résultat. Qui voulait une numérotation à la manière des tableaux, où la première ligne est la ligne 0, ne l'aura pas ici. Un champ vide se comporte pareil, et une valeur qui n'est pas un nombre non plus : « abc » donne 1.
Les départs négatifs, curieusement, fonctionnent, parce que −3 est truthy. Trois lignes commençant à −3 reviennent en « -3. », « -2. », « -1. » — cela ne sert à rien de précis, mais cela montre que le garde-fou porte sur la falsiness et non sur le signe. Les valeurs fractionnaires sont arrondies vers moins l'infini : 2,7 devient 2 et −2,7 devient −3.
Le retour, qui n'est pas symétrique
remove-line-numbers n'a aucune option. Il applique un seul motif à chaque ligne : espaces ou tabulations de tête, puis le numéro et son marqueur — des chiffres suivis d'une tabulation, ou des chiffres entre crochets ou précédés d'un dièse, ou des chiffres suivis d'un point, d'une parenthèse fermante, d'un deux-points, d'un crochet fermant ou d'une flèche — puis une seule espace, ou la fin de la ligne. Tout ce qui est reconnu est supprimé, une fois par ligne. Deux détails de cette phrase font tout le travail : le marqueur doit être suivi d'une espace, et l'espace consommée est exactement une.
Passe les onze séparateurs dans l'outil et huit survivent au trajet : le point, la parenthèse, le deux-points, la tabulation, « [1] », « 1] », « #1 » et « 1 → » reviennent exactement au texte d'origine. Trois n'y survivent pas, et l'omission est volontaire. « 1 - alpha », « 1 | alpha » et « 1 alpha » reviennent inchangés, numéros toujours attachés, parce que « 5 - 3 = 2 », « 10 - 20 people », « 1 | Alice | 30 » et « 007 James » ont exactement la même forme et sont bien plus souvent du contenu que de la numérotation. Un outil de suppression qui annulerait ces trois-là mangerait une ligne de tableur chaque fois que quelqu'un en collerait une.
Le motif se terminait par une suite gourmande d'espaces, qui emportait l'indentation propre au texte ; il n'en prend plus qu'une seule. Numérote cinq lignes de JavaScript avec une fonction, un if et un return, dénumérote-les, et le fichier revient octet pour octet, indentation comprise. YAML et Python se comportent pareil, et c'est là que cela compte le plus : dans ces deux langages, un résultat aplati n'est pas seulement laid, il ne veut plus dire la même chose.
Un outil de suppression ne sait pas à qui appartient le numéro
C'est la limite honnête de toute l'idée, et la règle de l'espace la resserre sans la supprimer. « 1. Laver le riz » est une ligne numérotée si c'est l'outil qui a mis le 1, et du contenu si c'est le cuisinier. Rien dans la chaîne ne distingue les deux, et aucun motif ne le peut : ces deux lignes sont les mêmes octets. Exiger une espace après le séparateur écarte les accidents — « 3.14 is pi » et « 1.2.3 version » reviennent maintenant intacts, parce qu'un point décimal n'est jamais suivi d'une espace — mais cela n'écarte pas les coïncidences. « 12: 30 departure » revient toujours en « 30 departure ». « 2026. A year. » revient toujours en « A year. » Les deux sont, caractère pour caractère, ce qu'écrit add-line-numbers ; sur une ligne que personne n'a numérotée, c'est donc toujours une perte de données.
Deux choses gardent le cas ordinaire à l'abri. La suppression a lieu une fois par ligne et s'arrête au premier séparateur : une liste de prix écrite à l'anglaise, numérotée, donne « 1. 12.50 Coffee », et la dénuméroter reconnaît « 1. » puis s'arrête, rendant « 12.50 Coffee » intact ; une liste qui avait déjà ses propres numéros, « 1. 1. alpha », perd exactement un niveau. Et cette ligne de prix survit désormais même sans la numérotation, parce que le point de « 12.50 » n'est pas suivi d'une espace. L'aller-retour est donc sûr sur n'importe quel texte, indenté ou plat, avec l'un quelconque des huit séparateurs. Ce qui mord encore, c'est l'outil de suppression seul, appliqué à un texte que personne n'a numéroté, sur le petit ensemble de lignes qui ressemblent à sa propre sortie.
Comprendre pourquoi quelque chose est sûr est plus utile que la liste. Un CSV d'identifiants survit — « 1024, Dupont, 42 » revient intact — parce que le caractère après les chiffres est une virgule, et la virgule n'entre dans aucune des formes de marqueur. « 100 units of flour » et « 007 James » survivent parce qu'une simple espace n'en fait pas partie non plus. Les décimales et les versions sémantiques sont sûres elles aussi, mais pour l'autre raison : « 3.14 » et « 1.2.3 » portent bien un point, et ce qui les sauve, c'est qu'aucune espace ne le suit. Ce qui est en danger, c'est l'ensemble étroit où un nombre, un marqueur reconnu et une espace arrivent dans cet ordre : les années utilisées comme titres, « 12: 30 » écrit avec une espace après le deux-points, et — nouveauté depuis l'élargissement du jeu de marqueurs — les appels de note du type « [1] » et les lignes qui s'ouvrent sur « #1 ».
Mener la relecture sans rien perdre
Garde l'original non numéroté quelque part où tu ne l'écraseras pas, et traite la version numérotée comme une impression : quelque chose à lire, citer et annoter, pas à modifier et renvoyer. Chaque correction récoltée sous la forme « ligne 47, remplacer X par Y » s'applique proprement à l'original, et il n'y a jamais besoin de retirer les numéros.
Si tu comptes vraiment dénuméroter plus tard, évite exactement trois séparateurs : le tiret, la barre verticale et l'espace simple. Tout le reste du menu — point, parenthèse, deux-points, tabulation, « [1] », « 1] », « #1 », « 1 → » — se retire sans peine. Préfère la tabulation si le texte doit passer près d'un tableur : elle met les numéros dans leur propre colonne.
Numéroter du code que tu comptes recoller est désormais tenable, ce qui n'était pas le cas : avec un point, une parenthèse, un deux-points ou une tabulation, le fichier revient octet pour octet, indentation comprise. Cela reste rarement le bon geste — une relecture de code dispose de meilleurs instruments : un diff, une pull request, ou simplement les numéros de ligne que l'éditeur vous affiche déjà à tous les deux — mais si tu le fais, choisis l'un de ces quatre et fais d'abord l'aller-retour sur une copie.
| Entrée | Résultat | Pourquoi |
|---|---|---|
| « Commencer à » réglé sur 0, deux lignes | 1. a et 2. b | Number(start) || 1 — zéro est falsy, il devient donc 1 |
| « Commencer à » réglé sur −3, trois lignes | -3. a, -2. b, -1. c | Un nombre négatif est truthy, le garde-fou le laisse passer |
| Un texte de 102 lignes, séparateur par défaut | « 1. » en haut, « 102. » en bas | Aligné à droite avec des espaces ; la largeur vient du dernier numéro |
| Texte se terminant par un saut de ligne | Une ligne vide numérotée à la fin | Le découpage sur les sauts de ligne donne un morceau de plus qu'il n'y a de lignes de texte |
| « 1 - alpha » dans remove-line-numbers | Inchangé | Le tiret est écarté volontairement : « 10 - 20 people » est bien plus souvent du contenu que de la numérotation |
| Cinq lignes de JavaScript indenté, numérotées puis dénumérotées | Le code revient octet pour octet, indentation comprise | Le motif ne prend qu'une seule espace après le séparateur, pas une suite gourmande |
| « 3.14 is pi », jamais numérotée, dans l'outil de suppression | Inchangé | Un séparateur doit être suivi d'une espace, et un point décimal ne l'est jamais |
| « 1024, Dupont, 42 », jamais numérotée, dans l'outil de suppression | Inchangé | La virgule n'entre dans aucune des huit formes de marqueur : rien ne correspond |
| « 1. 12,50 Café », numérotée par l'outil, dans l'outil de suppression | « 12,50 Café » — l'aller-retour ne perd rien | Le remplacement s'exécute une fois par ligne et s'arrête au premier séparateur |
Questions fréquentes
- Puis-je faire commencer la numérotation à 0 ?
- Non, et aucune astuce ne contourne cela. L'outil lit le champ comme Number(start) || 1. Zéro est falsy en JavaScript : l'expression le jette et rend 1 — taper 0, laisser le champ vide et taper un mot produisent tous une liste qui commence à 1. Vérifié avec 0, « 0 », « » et « abc » : les quatre donnent la même sortie. S'il te faut une numérotation à partir de zéro, numérote depuis 1 et retranche un mentalement, ou numérote depuis −1 si le décalage compte plus que le signe : les départs négatifs fonctionnent, car un nombre négatif est truthy.
- Les numéros resteront-ils alignés une fois le texte passé à 100 lignes ?
- Oui. La largeur est calculée à partir du dernier numéro avant toute écriture, et chaque numéro est complété à gauche par des espaces jusqu'à cette largeur. Un texte de 102 lignes commence avec deux espaces devant la ligne 1 et aucun devant la ligne 102 : les points forment une colonne droite. Pas de zéros de tête — tu obtiens « 7. », jamais « 007. ». Une conséquence surprend : un texte de 99 lignes utilise une largeur de deux, le même texte avec une ligne de plus une largeur de trois, donc chaque ligne change d'une espace. Si tu compares deux versions numérotées avec un diff, c'est pourquoi tout le fichier paraît modifié. Compare plutôt les originaux.
- remove-line-numbers annule-t-il toujours add-line-numbers ?
- Non, mais les raisons ont changé. Il reconnaît huit des onze séparateurs — point, parenthèse fermante, deux-points, tabulation, « [1] », « 1] », « #1 » et « 1 → » — et laisse volontairement le tiret, la barre verticale et l'espace simple, parce que « 10 - 20 people », « 1 | Alice | 30 » et « 007 James » ont la même forme et sont le plus souvent du contenu. Avec un séparateur reconnu, l'aller-retour est désormais identique au bit près, indentation comprise : cinq lignes de JavaScript avec un corps de fonction indenté de quatre puis huit espaces sont entrées et revenues identiques, et de même pour du YAML, du Python et une liste de prix plate.
- J'ai passé l'outil de suppression sur une liste de prix et il en a mangé une partie. Que s'est-il passé ?
- Il ne peut plus le faire. L'outil supprimait autrefois les chiffres de tête suivis d'un point, d'une parenthèse fermante, d'un deux-points ou d'une tabulation, sans rien exiger derrière — d'où « 3.14 is pi » devenu « 14 is pi » et « 12.50 Coffee » devenu « 50 Coffee ». Le motif exige désormais une espace, ou la fin de la ligne, après le séparateur, et un point décimal n'est jamais suivi d'une espace : « 3.14 is pi », « 1.2.3 version » et « 12.50 Coffee » reviennent tous intacts. Ce qu'il peut encore prendre, c'est une ligne dont la forme est exactement celle de sa propre sortie — « 2026. A year. » donne « A year. », « 12: 30 departure » donne « 30 departure » — et, depuis l'élargissement du jeu de marqueurs, les appels de note : « [1] See note » donne « See note ». Une liste séparée par des virgules est sûre dans tous les cas, la virgule n'entrant dans aucune forme de marqueur.
- Faut-il numéroter du code source pour une revue de code ?
- En général non, même si ce n'est plus risqué. Le code porte déjà des numéros de ligne partout où on le lit — dans la marge de l'éditeur, dans un diff, dans l'interface de revue de n'importe quelle plateforme — donc le numéroter ajoute surtout du bruit. Il survit désormais à l'aller-retour : avec un point, une parenthèse, un deux-points ou une tabulation, numéroter un fichier indenté puis le dénuméroter le rend octet pour octet, indentation comprise, ce qui n'était pas vrai avant. Trois séparateurs ne sont toujours jamais retirés — le tiret, la barre verticale et l'espace simple — évite-les donc si les numéros doivent repartir. La numérotation trouve sa place sur un texte sans numéros propres, lu en dehors d'un outil qui en fournit : un contrat diffusé comme document, un fichier de sous-titres discuté dans un fil de discussion, une liste de chaînes envoyée à un traducteur. Si tu relis du code et que la plateforme est hors de portée, citer le code dans un bloc et le désigner par nom de fonction reste la voie la plus calme.
Articles qui pourraient t'intéresser
Tous les guides →Outils similaires
Tout ce qui suit décrit ce que font ces quatre outils aujourd'hui, vérifié en exécutant leur propre code sur les entrées exactes reproduites dans chaque article — et non ce qu'une norme leur imposerait. Quand un outil se trompe sur un cas, c'est dit franchement plutôt que contourné, et rien n'a été modifié pour qu'un article se lise mieux. Deux conséquences. Passe toute transformation sur une copie d'abord et compare les deux bouts : un outil de texte qui supprime quelque chose ne le dit pas. Et considère un secret comme partagé dès qu'il quitte la page — le coller dans une conversation, un ticket ou un dépôt le brûle, aussi bien ait-il été généré.
Sources
Tu as repéré une erreur dans cet article ?