Wie füge ich einer Datei permanente Zeilennummern hinzu?


21

Ich habe eine Textdatei wie diese (mit gVim unter Windows)

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

Ich möchte jeder Zeile in der Datei eine Nummer hinzufügen. Nicht verwenden :set number, sondern wie folgt die Nummer als Text vor jeder Zeile einfügen, damit die Nummer Teil der Datei ist.

1. foo bar baz quux 
2. corge grault garply 
3. waldo fred plugh 
[...~150 more lines...]
155. xyzzy thud

awkist wahrscheinlich das Werkzeug für diesen Job. Aber ich bin auf Windows (seufz).
Roblogic

Beantwortet hier schon ,
egal

1
Vielleicht ... Oder ist das allgemeiner?
muru

Es ist ähnlich, aber ich würde nicht wissen, was permanente Leitungsnummern sind. Zweitens betrifft die andere Frage alle Zeilen (und die Antwort tut dies) für gVim unter Windows, und dies ist eine einfache nummerierte Liste für einen Absatz, nur in Klartext.
Kenorb

3
Nun, ich vermute, dass der Beitrag "permanent" verwendet, um anzuzeigen, dass der Puffer geändert werden soll und dass die Zahlen keine rein visuelle Sache sind (so wie Sie). Der Grund für die Angabe von gvim unter Windows besteht darin, externe Dienstprogramme wie catoder zu vermeiden nl, die zwar Zahlenzeilen enthalten können, unter Windows jedoch nicht allgemein verfügbar sind (wie OP aus ihrem Kommentar zu hervorgeht awk). Die beiden Top-Lösungen sind pure Vim. Schließlich sind alle Zeilen gegen einen Para nur eine Frage der Bereichsauswahl. Ganz klar kein großes Problem.
muru

Antworten:


36

In reiner Vim Mode:

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

Erläuterung:

:%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

Siehe :help \=und :help line().

Die Verwendung eines Ausdrucks im Ersatzteil ist sehr mächtig und FWIW ein ziemlich guter Einstiegspunkt in Vimscript.


Wie kann ich diesen sehr nützlichen Befehl zu einer Keymap in vimrc hinzufügen?
Cosmicraga

So gelangen Sie zum :help sub-replace-expression
VIM-Hilfethema

9

Eine nette Sache an Vim-Makros ist, dass sie sich wiederverwenden können (sie können sich selbst aufrufen):

  1. Register löschen q: qqq
  2. Fügen Sie die Zahl in die erste Zeile ein: ggI1.(Leerzeichen nicht vergessen!)
  3. Gehen Sie zurück zum Zeilenanfang und beginnen Sie mit der Aufzeichnung eines Makros: 0qq
  4. Kopieren Sie die Nummer: yW
  5. Verschiebe eine Zeile nach unten und füge die Zahl ein: +P
  6. Gehen Sie zurück zum Zeilenanfang und erhöhen Sie die Zahl: 0<c-a>
  7. Gehen Sie zurück zum Zeilenanfang (damit das Makro nicht abbricht, wenn es zweistellig wird!): 0
  8. Rufen Sie das Makro einmal auf, um es rekursiv zu machen. An diesem Punkt gibt es noch nichts im Register q, so dass nichts passieren wird: @q.
  9. Speichern Sie das Makro: q
  10. Rufen Sie das Makro noch einmal auf und sehen Sie zu, wie die Funken fliegen !: @@

Das Makro ruft sich dann selbst weiter auf, bis es das Ende der Datei erreicht.

Sie können den rekursiven Makrotrick auch für viele andere ähnliche Probleme verwenden.

Wenn Sie aus irgendeinem Grund kein rekursives Makro verwenden möchten, können Sie die Schritte 1 und 8 auslassen und einen Zähler verwenden , um das Makro mehrmals 100@qauszuführen , z. B. wird das Makro q100-mal ausgeführt.


1
Mächtiges Zeug, ich verneige mich vor deiner Meisterschaft. Makros sind für mich wie schwarze Magie ...
Roblogic

1
@ropata, ein Makro ist nur eine Folge von Befehlen (meistens) im normalen Modus.
Romainl

1
@romainl Ich denke, es ist besser, sich das als eine Folge von Tastenanschlägen vorzustellen .
Rich

2
@Rich, es kann eine Folge von vielen Dingen sein, einschließlich ex-Befehlen.
Romainl

2
@romainl Ja, deshalb denke ich, ist es am besten, wenn man sich das als Tastendruck vorstellt. Es wird genau das wiedergegeben, was Sie auf der Tastatur eingeben (einschließlich der ex-Befehle), als hätten Sie alles manuell eingegeben.
Rich

7

Ich verwende gerne den Befehl vim global, um solche Aufgaben zu erledigen. Dies gilt für das Hinzufügen einer Iteration am Anfang einer Zeile oder das Ändern eines Symbols im Text. Es sieht komplizierter aus als die anderen Lösungen, ist aber ein ziemlich flexibles Muster, das Sie verwenden können, wenn Sie es zur Hand haben, und lässt sich leicht ohne viel Nachdenken ändern.

Wählen Sie zunächst Ihren Bereich aus (welche Linien möchten Sie anwenden). Normalerweise verwende ich Markierungen (z. B. main der ersten und mbin der zweiten Zeile , aber Sie können auch Zeilennummern oder eine visuelle Auswahl verwenden) und gebe dann eine Änderung des folgenden Befehls ein (derzeit für Ihren Anwendungsfall optimiert).

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

Dekonstruktion

:let i=1

Dies setzt eine Variable imit einem Startwert. Normalerweise beginnen Listen mit 1, also setze ich i auf 1.

|

Die Leiste startet einen neuen Befehl

'a,'b

Dies legt den Bereich des nächsten Befehls fest. Ich gehe von Punkt azu Punkt b, der in der ersten und letzten Zeile Ihrer Liste steht.

g/^/

Dies ist der globale Befehl. Es durchsucht die Datei (oder den Bereich) nach einem bestimmten regulären Ausdruck und führt den Rest der Befehlszeile in jeder der übereinstimmenden Zeilen aus. Ich passe jede Zeile an, indem ich nach "Zeilenanfang" suche. Wenn Sie Text mögen

Item some txt
other text

Item second item
whatever
Item third

und möchten diese Bezeichnungen nur vor Itemdie anderen Zeilen setzen und sie ignorieren, g/Item/oder g/^Item/stattdessen (unter der Annahme des wörtlichen Elementtexts)

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

Dadurch wird der reguläre Ausdruck ausgeführt, um den Zeilenanfang durch den Wert von iVerkettet mit einem zu ersetzen .. Im Allgemeinen können Sie dies für alle Fälle tun (ersetzen Sie beispielsweise das Etikett Itemdurch die Nummer).

|let i=i+1

Obwohl die Leiste einen neuen Befehl startet, richtet sie einen zweiten Befehl ein, der innerhalb des globalen Befehls ausgeführt wird, anstatt nach Abschluss des globalen Befehls. Das Ergebnis ist, dass wir inkrementieren, ibevor die nächste Zeile von g verarbeitet wird. Hier ist ein weiterer Ort der Flexibilität. Die Modifikation von i kann alles sein (inkrementiere um 2, rufe eine Funktion auf, die das nächste Element der Fibonacci-Sequenz erzeugt, was auch immer).


7

Fügen Sie allen Zeilen Zahlen hinzu

Es können Befehle :%!nl -baoder verwendet :%!cat -nwerden, die allen Zeilen Zeilennummern hinzufügen.

Unter Windows muss Cygwin / MSYS / SUA installiert sein.

Hinzufügen von Zahlen zu ausgewählten Zeilen

Um Zahlen nur für ausgewählte Zeilen hinzuzufügen, wählen Sie diese im visuellen Modus ( vund mit Cursorn) aus. Führen Sie anschließend den folgenden Befehl aus: :%!nl(Leerzeilen ignorieren) oder :%!cat -n(Leerzeilen eingeschlossen).

Formatierung

Um zusätzliche Leerzeichen zu entfernen, markieren Sie sie im Sichtblock ( Ctrl+ v) und entfernen Sie sie ( x).

Um einige Zeichen (in ., :, )) nach den Zahlen, wählen Sie sie in der visuellen Block ( Ctrl+ v), dann fügen Sie die Zeichen ( Adie Zeichen eingeben, dann beenden Sie mit Esc).


2
Dies ergibt nicht die gleiche Formatierung wie in der Frage angegeben. Mir gefällt jedoch die Einfachheit der Lösung.
Karl Yngve Lervåg

@ KarlYngveLervåg Danke, habe das in die Antwort aufgenommen.
Kenorb

5

Eine Modifikation von Romainls Antwort :

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

Dadurch werden nicht nur Zeilennummern hinzugefügt , sondern auch vorhandene Zeilennummern ersetzt, sofern diese bereits vorhanden sind. Wenn Sie eine Zeile in der Mitte eingefügt haben, wird alles wie erwartet neu nummeriert.

Dies funktioniert, indem eine beliebige Zahl gefolgt von einem ersetzt wird. und ein Leerzeichen am Zeilenanfang mit einer neuen Nummer. Dies wird offensichtlich unterbrochen, wenn Sie eine Linie haben, die bereits mit diesem Muster beginnt. Verwenden Sie diese also mit Bedacht.

Der hinzugefügte Teil:

  • ^ - Linienanfang
  • \( - Neue Untergruppe starten
  • \d\+ - Passen Sie eine Ziffer einmal oder mehrmals an
  • \. - Ordne einen Punkt ( .) und ein Leerzeichen zu .
  • \) - Untergruppe beenden
  • \? - Machen Sie die Gruppe optional, damit es wie zuvor funktioniert, wenn in dieser Zeile noch keine Nummer steht.

Bonus-Tipp:
Um die Zeilennummern zu entfernen , können Sie dasselbe Muster verwenden, wobei der Repalce-Teil leer bleibt:

:%s/^\(\d\+\. \)\?//

5
I1. <esc>^qqyWjP^<C-a>q

Dadurch werden die ersten beiden Zeilen nummeriert, und Sie können drücken, @qum nachfolgende Zeilen zu nummerieren (oder beispielsweise eingeben, 18@qwenn Sie insgesamt 20 Zeilen nummerieren möchten).

Erläuterung:

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

Dies hat den Vorteil, dass keine externen Befehle erforderlich sind. Dies ist hilfreich, wenn Sie beispielsweise mit Vim unter Windows arbeiten.


Nach der Eingabe befinden 1. <esc>hSie sich in der zweiten Spalte, nicht in der ersten Spalte. Ich würde das hmit ersetzen 0, wonach ich denke deine Lösung sollte sehr gut sein.
Karl Yngve Lervåg

@ KarlYngveLervåg Hoppla, das war ein Tippfehler. Danke, habe es behoben.
Türknauf

Kein Problem. Sie haben die Erklärung jedoch noch nicht aktualisiert. Außerdem: Wartet auf vielen Tastaturen ^auf ein zweites Zeichen, um Tastenkombinationen wie zuzulassen ^a -> â. Ich bin immer noch der Meinung, dass es die beste Lösung ist, aber ich denke, dies sollte auch erwähnt werden.
Karl Yngve Lervåg

3

Ich denke, die gewählte Antwort ist die beste, aber im Geiste der Vielfalt biete ich eine Alternative mit einem externen Programm an:

:%!cat -n

Dies filtert Ihren gesamten Puffer (wie durch gekennzeichnet %) durch das externe Programm cat, wobei das -nFlag jeder Eingabezeile eine Zeilennummer voranstellt.

Dies setzt natürlich voraus, dass Sie catinstalliert haben, was (wahrscheinlich) für alle Unix-ähnlichen Systeme gilt.

Schauen Sie sich :help :range!für weitere Details zu den Filtern durch externe Programme.


1
Mir ist klar, dass der Fragesteller gVim unter Windows verwendet, sodass diese Lösung dort wahrscheinlich nicht funktioniert. Ich denke jedoch, dass es immer noch eine Gelegenheit für andere bietet, daraus zu lernen.
tommcdo

Wenn Sie dies installiert msysgitund Ihrem PATH hinzugefügt haben (IIRC ist eine Installationsoption), sollte diese Lösung auch unter Windows funktionieren.
Martin Tournoij

4
cat -nist nicht POSIX, nlist es aber , daher ist es möglicherweise eine bessere Option.
muru

2

Eine etwas hackige Lösung könnte die folgende sein (alles, was zwischen <und> steht, muss nach dem Drücken von Ctrl+ eingefügt werden v):

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

Dekonstruktion

:%normal {commands}

Führt den Normalmodus-Befehl in jeder durch den Bereich angegebenen Zeile aus, in diesem Fall in jeder Zeile

:redir @"

Leitet jede Ausgabe von ex-Befehlen in den unbenannten Puffer um.

:.=

ist ein ex-Befehl, der die aktuelle Zeilennummer ausgibt (leider mit vorangestelltem Zeilenumbruch)

:redir END

beendet die Umleitung zum unbenannten Puffer

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

fügt den Inhalt des unbenannten Puffers mit einem ein. und einen Tabulator vor jeder Zeile, um den Einfügemodus zu verlassen.

kdd

Geht eine Zeile weiter und entfernt die neue Zeile, die das Ergebnis des Befehls:. = ist.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.