In fast allen Büchern über Unix-Tools ist die Rede von ihnen: reguläre Ausdrücke. Hierbei handelt es sich um ein komplexes Regelwerk für Operationen aus dem Bereich „Suchen und Ersetzen“. Auf vielfältige Art und Weise läßt sich spezifizieren, wie eine Such-Operation zu erfolgen hat und welche Teile eines Suchbegriffes wie ersetzt werden sollen.
Nicht nur beim Programmieren gibt es immer wieder Situationen, in denen ein Textfragment gesucht und durch ein anderes ersetzt werden soll, wobei einfaches Suchen und Ersetzen aber nicht ausreicht. Für eine Textverarbeitung mag es noch genügen, als Regeln für das Suchen nach Texten lediglich Wildcards wie „*" und „?“ angeben zu können sowie eine Option zur Unterscheidung zwischen Groß- und Kleinschreibung zu haben.
Oft genug steht man jedoch vor dem Problem, daß die gewünschte Operation nicht mehr mit solchen Standardregeln zu lösen ist. Ein einfaches Beispiel: Bestimmte Worte eines Textes sollen gegen andere Begriffe ausgetauscht werden, aber nur dann, wenn sie am Beginn einer Zeile stehen. Diese Regel ist einfach, aber für die meisten Textverarbeitungen bereits ein unlösbares Problem.
Zwar werden auch in diesem Beispiel lediglich Teile eines Textes ersetzt, aber die Regel, nach der dies zu geschehen hat, ist recht ungewöhnlich. Sie läßt sich nicht mehr mit den üblichen Methoden erfassen. Reguläre Ausdrücke bieten in solchen Fällen eine Lösung. Mit einigen dieser Regeln wollen wir uns nun beschäftigen.
Aus dem täglichen Umgang mit Computern sind die Wildcards und .?“ bekannt, die insbesondere bei der Angabe von Dateinamen eine wichtige Rolle spielen und von den Unix-Shells ausgewertet werden. „*" steht dabei für eine beliebige Folge von Zeichen, „?" für genau ein Zeichen. Man kann diese Wildcards durchaus als sehr einfache reguläre Ausdrücke ansehen, wobei allerdings die Bedeutung der beiden Zeichen bei „echten" regulären Ausdrücken eine andere ist.
Dies soll anhand des Zeichens „*" verdeutlicht werden.
cde*f
Dieser reguläre Ausdruck steht für die Zeichenfolge „cd", gefolgt von beliebig vielen (auch keinem!) „e“ und genau einem „f“. Beispiele:
cdef cdeef cdeeeef cdf
Das „*“ steht hier im Gegensatz zu seiner Bedeutung für eine Shell nicht für eine beliebigeZeichenfolge, sondern gibt eine Regel an, die sich auf das vorausgehendeZeichen, im obigen Beispiel das „e“, bezieht. Diese Regel besagt, daß dieses Zeichen mehrfach oder auch überhaupt nicht Vorkommen muß.
Das Zeichen „+" steht dagegen für „einmal oder mehrmals".
cde+f
ist somit dem regulären Ausdruck „cde*f“ sehr ähnlich, trifft aber nicht zu auf die Zeichenfolge „cdf", da das „e“ hier gar nicht auftaucht.
Auch das „?" findet sich in diesem Kontext wieder. Es steht für „kein oder genau ein" Auftreten des vorausgehenden Zeichens. Bei einer Shell dagegen ist die Beschreibung „kein Zeichen" nicht erlaubt.
Als Platzhalter für ein beliebiges Zeichen steht bei regulären Ausdrücken der Punkt
cde.f
Auf diesen regulären Ausdruck passen Zeichenfolgen, die mit „cde“ beginnen, dann ein beliebiges Zeichen (ausgenommen \n) enthalten und schließlich mit einem „f" enden. Somit entspricht der dem, was innerhalb einer Shell das „?“ bewirkt. Und welcher reguläre Ausdruck paßt auf das, was eine Shell unter „*“ versteht? Es ist es muß also ein Punkt vor dem Stern stehen. So wird aus der Beschreibung „kein Zeichen oder mehrere Zeichen“ die Regel „ein Zeichen oder mehrere Zeichen“, so wie es auch eine Shell sieht.
[abcdeABCDE] Steht für eines der Zeichen in den eckigen Klammern
[a-eA-E] S. o, allerdings in gekürzter Form.
[^0-9] Paßt auf alle Zeichen, die keine Ziffern sind. Das ^ zu Beginn einer Liste negiert die Liste der nachfolgenden Zeichen.
^a Als erstes Zeichen eines regulären Ausdrucks steht ^ für „Zeilenanfang“. Damit trifft dieser reguläre Ausdruck auf jedes a zu, sofern es zu Beginn einer Zeile auftaucht.
a$ Paßt auf ein a am Ende einer Zeile oder eines Strings.
\bNet\b Trifft zu auf Net, aber nur wenn es als separiertes Wort auftritt, paßt also nicht auf Netscape oder MausNet. \b repräsentiert hier das Trennzeichen zwischen zwei Wörtern.
Übrigens: bedeutet unter Unix nicht dasselbe wie unter TOS. Ist unter TOS zum Löschen aller Dateien die Formulierung erforderlich, so genügt bei Unix bereits ein einfachs Dies liegt daran, daß unter Unix keine Ex-tensions in dem Sinne existieren, wie TOS oder DOS sie kennen. Daher wird der komplette Dateiname bereits durch ein erfaßt.
Werfen wir nun aber einen Blick auf weitere einfache reguläre Ausdrücke, um uns mit deren Syntax vertraut zu werden, die mitunter recht kryptisch sein kann (siehe Tabelle 1).
Nun fragt man sich natürlich, was wir mit unserem bisherigen Wissen anfangen können. Obwohl bisher nur sehr einfache Regeln berücksichtigt wurden, ist dies bereits eine ganze Menge und läßt reichlich Raum für Experimente. Die meisten Unix-Dienstprogramme, mit denen sich Texte bearbeiten lassen, unterstützen reguläre Ausdrücke, grep ist eines dieser Programme, sed oder auch die Editoren vi und GNU emacs sowie die nützliche Programmiersprache für Shellscripte perl sind weitere. Ein wenig Vorsicht ist allerdings insofern geboten, als daß nicht jedes Dienstprogramm die gesamte Palette regulärer Ausdrücke versteht. Die im folgenden aufgeführten Beispiele wurden mit GNU emacs 19.30 in der Praxis erprobt (Esc-x replace-regexp).
Wer mit regulären Ausdrücken auf der Kommandozeile arbeitet, beispielsweise in Verbindung mit grep, muß im Hinterkopf behalten, daß bereits die Shell versuchen wird, einige Zeichen zu expandieren.
grep cd*f dateiname
führt dazu, daß das Zeichen von der Shell ausgewertet wird und erst das Ergebnis an grep übergeben wird. Hier muß daher gequotet werden:
grep "cd*f" dateiname
So läßt sich das "*" vor der Interpretation durch die Shell „schützen“.
Wie eingangs erwähnt, kommen reguläre Ausdrücke vor allen Dingen beim Suchen und Ersetzen von Zeichenfolgen zum Einsatz. Die Anweisung „s“, gefolgt vom alten und neuen Wert in Form eines regulären Ausdrucks, steht bei vielen Unix-Dienstprogrammen für eine solche Operation.
/s/alt/neu/
In einem Programm, das reguläre Ausdrücke beim Ersetzen von Text unterstützt, wird mit dieser Beschreibung die Zeichenfolge alt durch neu ersetzt. Nicht unbedingt erwünscht ist dabei, daß aus dem Begriff Gehalt etwas weniger gehaltvolles wird, nämlich Gehneu. Dieses Verhalten magman von seiner Textverarbeitung gewohnt sein, aber zwingend ist es deshalb nicht. Dies beweist der folgende Ausdruck, der diesen Effekt beseitigt:
/s/\balt\b/neu/
Hier wird aus alt wirklich nur dann neu. wenn alt als separiertes Wort auftritt. (Was genau dabei unter „Wort“ zu verstehen ist, kann der weiterführenden Literatur entnommen werden.) Aber Vorsicht: Steht alt am Beginn bzw. Ende einer Zeile, so wird es von der obigen Regel nicht erfaßt, da in diesem Fall kein Wort-Trennzeichen vorausgeht bzw. folgt.
/s/^alt\|alt$/neu/
In diesem Beispiel schließlich wird alt dann ersetzt, wenn es am Anfang oder am Ende eines Strings bzw. einer Zeile steht. Das Zeichen „|“ bedeutet „oder“, ihm muß bei emacs ein „\“ vorausgehen.
Bereits an einfachen Beispielen läßt sich ersehen, welche Möglichkeiten die Modifikation von Texten durch reguläre Ausdrücke bietet. Zugegeben, die Syntax für reguläre Ausdrücke wird schnell kryptisch. Aber dennoch lohnt es sich, diesem Thema seine Aufmerksamkeit zu widmen. Schon bei einfachen Operationen kann die Verwendung grundlegender regulärer Ausdrücke ein Vielfaches derzeit einsparen, die man für eine Änderung benötigt, bei der per Hand editiert wird.
Gerade beim Einsatz komplexer regulärer Ausdrücke ist es allerdings wichtig, die Korrektheit der benutzten Regeln vor der praktischen Anwendung zu überprüfen. Andernfalls geht man das Risiko ein, einen Text unwiderruflich zu verstümmeln. Anhand der angeführten Beispiele wurde ja bereits deutlich, daß ein scheinbar eindeutiger Ausdruck doch nicht immer die Wirkung hervorruft, die man sich auf dem ersten Blick von ihm verspricht. Man sollte daher stets eine Kopie der Datei besitzen, auf die ein komplizierter regulärer Ausdruck angewendet wird, um Textpassagen zu modifizieren. Erst nachdem das Ergebnis überprüft wurde, mag man die ursprüngliche Datei löschen.
Da reguläre Ausdrücke von vielen Unix-Tools unterstützt werden, gibt es mehr als genug Literatur, in denen auf dieses Thema eingegangen wird, z. B. [1], [2], [3], [4]. Hier zeigt sich erneut, daß O’Reilly & Associates aus der Sicht des Unix-Anwenders für wirklich alle Lebenslagen Lösungen bereithalten.
US
Literatur:
[1] Dale Dougherty, „sed & awk“, O’Reilly & Associates, Inc. [2] Randal L. Schwartz, „Learnlng Perl“, O'Reilly & Associates, Inc. [3] Debra Cameron, Bill Rosenblatt, „Learnlng GNU Emacs“, O’Reilly & Associates, Inc. [4] Jerry Peek, Tim O’Reilly, Mike Loukldes, „Unix Power Tools“, O’Reilly & Associates/Bantam