Wie nummeriere ich eigentlich einen bestimmten Bereich?
Um in der aktuellen Datei jede Zeile durchzunummerieren, reicht folgendes:
CODE:
:%s/^/\=line('.')/
Hier wird jede Zeile ausgewählt (^) und für jede Zeile die Expression line('.') ausgewertet. line('.') gibt immer die aktuelle Zeilennummner zurück. Um Expressions auszuwerten, benutzt man den Ausdruck \=<expression> Das funktioniert aber nur, wenn es an erster Stelle im Replacement String steht.
Um nur einen bestimmten Bereich zu nummerieren, kann man den markierten Bereich markieren und danach wie folgt suchen/ersetzen:
CODE:
:'<,'>s/^/\=line('.')-line("'<")
Die Marker '< und '> werden automatisch gesetzt, wenn visuell markiert wird und zeigen auf die erste bzw. letzte markierte Zeile. Den Rest brauch ich wohl nicht mehr erklären...
Nun kann es aber sein, dass sich der Bereich nicht einfach markieren läßt, sich aber durch eine Suche selektieren läßt. Hier in diesem Text könnte man z.B. alle Zeilen nummerieren wollen, die mit ":" anfangen. Erschwerend kommt hinzu, dass man jeden Treffer um eins hochgezählt haben möchte, die Funktion line() also nicht mehr genutzt werden kann. Zum Nummerieren muß dann eine einfache Funktion geschrieben werden, die eine globale oder wie in diesem Fall Buffer-Variable nutzt:
CODE:
:let b:start=0
function! PlusEins()
let l:count=b:start
let b:start+=1
return l:count
endfunction
function! PlusEins()
let l:count=b:start
let b:start+=1
return l:count
endfunction
Nun kann man wie folgt durch nummerieren:
CODE:
:%s/^\zs\ze:/\=PlusEins()/
Okay, das ist schon etwas komplexer. Das kann man aber auch wie folgt vereinfachen:
CODE:
:let n=1|g/^\zs\ze:/s//\=n/|let n+=1
Hier wird zunächst eine Variable initialisiert (das ist unser Startwert für die Nummerierung). Dann wird für die aktuelle Datei ein :g Command ausgeführt. :g ist im Prinzip eine Verallgemeinerung von :s, denn es wird ein Muster gesucht, und für jede gefundene Stelle wird eine Aktion durchgeführt (:g/Muster/Command), in diesem Fall wird Suchen und Ersetzen durchgeführt mit einem 'leeren' Muster, weil das zu suchende Muster bereits im :g Abschnitt definiert wurde. Zum Schluß wird die Variable n noch inkrementiert. Okay, was heißt jetzt '\zs' und '\ze'? Damit wird im Suchen und Ersetzen Muster festgelegt, wo der Match anfängt und endet (also welcher Teil nachher ersetzt werden darf). Da ich die Zeile so lassen wollte, und nur zusätzlich die Ziffer hinzufügen wollte, selektiert es in diesem Fall nichts.
Wichtig zu wissen ist, dass alles was nach \= kommt als Expression ausgewertet wird. Möchte man jetzt zusätzlich noch Text anfügen, muß dies als Expression geschehen. Z.B. möchte man hinter der Ziffer vielleicht noch ein Leerzeichen haben:
CODE:
:let n=1|g/^\zs\ze:/s//\=n.' '/|let n+=1
Möchte man im zu ersetzenden Text jetzt Bezug auf Teilpatterns nehmen, was ja normalerweise durch \1...\9 nehmen, nimmt man dafür die Funktion submatch(1)...submatch(9). Zum Beispiel könnte man die Nummerierung nicht vor den Doppelpunkt schreiben, sondern in der Zeile darüber:
CODE:
:let n=1|g/^:.*$/s//\=n."\r".escape(submatch(0),'')/|let n+=1
Hier wird mit submatch(0) auf das komplette Muster zurückgegriffen und returnt. Da dabei anscheinend die Backslashes verloren gehen, muß man diese nochmal escapen, was mit der Funktion escape() gemacht wird. Das Muster "\r" wird benutzt, um einen Zeilenumbruch einzufügen.
Merke: Innerhalb von vim, wird im Replacement-Teil eines regulären Ausdruckes immer mit \r ein Zeilenumbruch eingefügt, nie mit \n, denn \n wird genutzt, um ASCII 0 (NULL) zu repräsentieren. Beim Schreiben der Datei wird dann der eigentliche physische Zeilenumbruch im Format Unix (LF), DOS (CRLF) oder MAC(CR) eingefügt. Möchte man aber nach einem Zeilenumbruch suchen, ist \n der richtige Ausdruck.
