Betrachten wir Variablennamen in typischen Hochsprachen wie Pascal und C. Es handelt sich dabei gewöhnlich um Zeichenfolgen, die aus einem Buchstaben bzw. Underscore (_) bestehen, dem beliebig viele Buchstaben, Ziffern und Underscores folgen können. Das ist zwar weder aufregend noch neu, dafür aber eine konkrete Anwendung eines, wenn auch nur verbal formulierten regulären Ausdrucks zur Syntaxspezifikation. Die Menge der Zeichenketten, die diesem einfachen Muster entsprechen, ist unendlich, so daß sie nicht durch die Aufzählung aller ihrer Elemente angegeben werden kann. Unter Verwendung des genannten Musters ist die Lösung unseres Problem allerdings mehr als trivial.
Vielleicht läßt sich hier schon die Mächtigkeit des Konzepts erahnen. Um nun die ihm innewohnenden Potenzen nutzen zu können, ist natürlich etwas Arbeit zu investieren, die aber nicht gescheut werden sollte, da als Lohn der Zugang zur faszinierenden Welt der regulären Ausdrücke winkt, die auch "alte Hasen" gelegentlich recht ordentlich verblüfft.
Was ist nun konkret Sache? Die Theoretiker beantworten diese Frage mit der Feststellung, daß sich mittels regulärer Ausdrücke genau die regulären Sprachen beschreiben lassen, also diejenigen, denen lineare Grammatiken zugrunde liegen und die genau von den endlichen Automaten akzeptiert werden. Punkt. Das ist korrekt, trägt aber kaum zur Demystifizierung der Angelegenheit bei. Aber keine Angst. Es ist zum Glück nicht nötig, diesen Satz zu verstehen oder gar tiefer in die Automatentheorie bzw. die Theorie der formalen Sprachen einzudringen. Wie so oft im Leben geht es auch einfacher und praxisorientierter.
Vor der Diskussion der konkret bei VIM 4.6 zur Verfügung stehenden regulären Ausdrücke sei darauf hingewiesen, daß es, speziell im UNIX-Umfeld, neben Vi & Co. viele Werkzeuge und Sprachen gibt, die reguläre Ausdrücke unterstützen. Zu ihnen zählen z.B. grep / egrep, lex, ed, sed, awk, Perl, Tcl und Python.
Um es dem Anwender nicht ganz so einfach zu machen, unterscheiden sie sich jeweils mehr oder minder geringfügig hinsichtlich des angebotenen Leistungsumfangs und der verwendeten Syntax :-). Aber das kann ja alte Computer-Freaks nicht schocken. Wenn einmal das Prinzip klar ist, reichen in der Regel einige Versuche am betreffenden Objekt aus, um die gewünschten Resultate zu erzielen.
Trial and error ist eben oft ein brauchfähiger Weg. Der VIM kann dabei als eine sehr gute, weil interaktive Übungsumgebung angesehen werden. Geht mal was schief, ist das kein Malheur. Nach einem kühnen Undo ist ja der alte Zustand wieder da, und ein neuer Versuch klappt bestimmt schon besser.
Wie immer gilt: "Übung macht den Meister" oder "Versuch macht klug".
Beispiel: abc\|def umfaßt sowohl abc als auch def.
Beispiel: abc[0-9]def umfaßt die Zeichenketten, die mit abc beginnen, dann eine Ziffer (0..9) folgen lassen und mit def enden.
Spezielle Zeichen hinter einem Atom:
magic nomagic Anzahl des Auftretens des Atoms * \* 0 ... unendlich \+ \+ 1 ... unendlich (nicht bei Vi)\= \= 0 oder 1 Mal (nicht bei Vi)
Beispiel:
magic nomagic dadurch beschrieben .* .\* ganze Zeile, auch wenn leer .\+ .\+ jede nichtleere Zeichenkette guu\=t guu\=t gut oder guut
magic nomagic Bedeutung ^ ^ am Musteranfang: Zeilenbeginn $ $ vor \| oder am Musterende: Zeilenende . \. beliebiges einzelnes Zeichen \< \< Beginn eines Wortes \> \> Ende eines Wortes \e \e <Esc> (Escape) \t \t <Tab> (Tabulator) \r \r <CR> (Carriage Return) \b \b <BS> (BackSpace) ~ \~ entspricht der zuletzt spezifizierten Ersetzungs-Zeichenkette
Beispiel: \(^a\) für das Zeichen a am Zeilenanfang
Falls die Zeichenfolge mit einem ^ beginnt, so gehören diejenigen Zeichen zum Bereich, die nicht explizit genannt sind. Werden zwei Zeichen durch - (Strich) getrennt, so ist das eine Abkürzung für die Liste der ASCII-Zeichen, die beim erstgenannten Zeichen beginnt und beim letztgenannten endet, z.B. 0-9 für alle Ziffern 0 bis 9.
Soll die schließende eckige Klammer selbst zum Bereich gehören, dann muß sie als erstes Zeichen hinter der öffnenden Klammer bzw. dem negierenden ^ angegeben werden. Bsp.:
Gehört ein - (Strich) zum Bereich, so hat dessen Spezifikation am Anfang bzw. am Ende zu erfolgen.
Anmerkungen:
Beispiele:
^beep( beep( am Zeilenanfang [a-zA-Z]$ jeder Buchstabe am Zeilenende /hier \(vorn\|hinten\) sind Zeile, in der zwischen den Wörtern hier und sind eines der Wörter vorn oder hinten steht, jeweils durch Leerzeichen getrennt
Bei den Ersetzungskommandos folgt hinter dem Argument, das die zu ersetzende Zeichenkette beschreibt, ein weiteres Argument, das die Ersatz-Zeichenkette angibt, wobei Rückbezüge auf Teile der gefundenen, zu ersetzenden Zeichenkette möglich sind.
Einige Zeichen der Ersatz-Zeichenkette haben daher eine Sonderbedeutung. Sofern es sich um Ctrl-Zeichen handelt, sind diese mit vorangestelltem Ctrl-V einzugeben. Ggf. kann die Sonderbedeutung durch Voranstellen eines Backslash aufgehoben werden.
magic nomagic Bedeutung & \& Ersatz durch die gefundene Zeichenkette \& & Ersatz durch & \0 Ersatz durch die gefundene Zeichenkette \1 Ersatz durch die dem ersten Teilmuster entsprechende Zeichenkette \2 Ersatz durch die dem zweiten Teilmuster entsprechende Zeichenkette .. .. \9 Ersatz durch die dem neunten Teilmuster entsprechende Zeichenkette ~ \~ Ersatz durch die Ersatz-Zeichenkette der vorigen Substitution \~ ~ Ersatz durch ~ (Tilde) \u Ersatz durch das groß geschriebene Folgezeichen \U Ersatz durch die groß geschriebenen Folgezeichen \l Ersatz durch das klein geschriebene Folgezeichen \L Ersatz durch die klein geschriebenen Folgezeichen \e Beendigung von \U, \L, \u und \l \E dieselbe Wirkung wie \e Ctrl-M Zeilenumbruch an dieser Stelle \r wirkt wie Ctrl-M (Zeilenumbruch) Ctrl-V Ctrl-M symbolisiert das Zeichen Ctrl-M \n symbolisiert das Zeichen <NUL> \b symbolisiert das Zeichen <BS> \t symbolisiert das Zeichen <Tab>
Beispiele:
Nachfolgend werden einige Ersetzungen gezeigt, die alle das Kommandos :s nutzen. Die Syntax dieses Kommandos kann beispielweise der Online-Hilfe entnommen werden.
:s/a\|b/xxx\0xxx/g ersetzt in der aktuellen Zeile a gegen xxxaxxx und b gegen xxxbxxx :s/\([abc]\)\([efg]\)/\2\1/g kehrt in der aktuellen Zeile die Reihenfolge der Zeichen aller Zeichenpaare um, die mit a, b oder c beginnen und mit e, f oder g enden :10s/abcde/abc^Mde/ fügt in Zeile 10 beim ersten Auftreten der Zeichenfolge abcde zwischen c und d eine Zeilenschaltung ein :.,$s/$/\r/ fügt im Bereich von der aktuellen Zeile bis zum Dateiende an jede Zeile eine weitere Zeilenschaltung an :%s/^M//g löscht alle Carriage-Return-Zeichen im Text :s/.*/& &/ dupliziert den Inhalt der aktuellen Zeile mit Leerzeichen als Trenner :s/\<[a-z]\+\>/\U&\e!/ wandelt alle Zeichen des ersten nur aus Kleinbuchstaben bestehenden Wortes der aktuellen Zeile in Großbuchstaben um und hängt ein ! an Anmerkung: Sofern die Option ignorecase gesetzt ist, erfolgt keine Beachtung der Groß- und Kleinschreibung. D.h., es wird das erste nur aus Buchstaben (Klein- und Großbuchstaben) bestehende Wort der aktuellen Zeile in angegebener Weise manipuliert.
Auch bei den Kommandos :g und :v lassen sich die zu bearbeitenden Zeilen mittels regülärer Ausdrücke spezifizieren:
:g/^$/d löscht alle leeren Zeilen, d.h. diejenigen, die lediglich aus der Zeilenendekennzeichnung bestehen :g/^(/s/a/b/g in allen Zeilen, die mit einer runden öffnenden Klammer beginnen, werden alle Buchstaben a gegen b ersetzt :v/z$/d löscht alle Zeilen, die nicht auf z enden
Holger Trapp, 26. Januar 1997, 26. Juni 1998