Grundlagen

Reguläre Ausdrücke

Reguläre Ausdrücke (RE, Regular Expressions) wurden von 1956 S.C. Kleene eingeführt und sie erwiesen sich als sehr effektiv, um Zeichenketten zu beschreiben.

REs werden dann verwendet, wenn man die Form einer Zeichenkette (String) angeben will - sie beschreiben also Klassen von Strings. Es ist zum Beispiel einfacher die Form der natürlichen Zahlen als "eine Zeichenkette, bestehend aus einer oder mehreren Ziffern aus der Menge {0,1,2,3,4,5,6,7,8,9}" zu definieren, als alle Zahlen von 0 bis unendlich aufzuzählen. Reguläre Ausdrücke sind eine Schreibweise, mit der man solche Klassen eindeutig beschreiben kann.

Man sagt eine RE passt auf eine Zeichenkette, wenn diese in der von der RE umrissenen Klasse enthalten ist. Häufig werden REs verwendet, um aus einem String einen Teilstring heraus zu picken, welcher von der RE beschrieben werden kann. Dabei gilt das Prinzip der längsten Übereinstimmung (longest match), was heißen soll dass dies der längste Teilstring ist, auf den die RE passt. In diesem Zusammenhang spricht man auch davon, REs sind greedy.

Tabelle 1. Erweiterte Reguläre Ausdrücke (Extended Regular Expressions)

Regulärer AusdruckErklärung
xdas Zeichen 'x'
\xwenn x in [abfnrtv] dann die ANSI C-Interpretation davon, sonst x selber, z.B. \*
\123das Zeichen mit oktalem ASCII-Code 123
\xe5das Zeichen mit hexadezimalem ASCII-Code e5
.jedes beliebige Zeichen außer \n (newline)
[xyz]eine "character class": x ODER y ODER z
[ako-sP]eine "character class" mit einer Bereichsangabe, also a ODER k ODER ein Character aus dem Bereich o BIS s ODER P
[^x-z]eine "negated character class": Jedes Zeichen außer x bis z
(r)die RE r selber
rsdie RE r gefolgt von der RE s
r|sdie RE r ODER die RE s
r*die RE r null oder mehrere male
r+die RE r ein oder mehrere male
r?die RE r null oder ein mal
r{2,6}die RE r zwei bis sechs mal
r{2,}die RE r zwei oder mehrere male
r{,6}die RE r null bis sechs mal
r{4}die RE r genau vier mal
^rdie RE r am Anfang der Zeile
r$die RE r am Ende der Zeile
[:str:]mit str eine der folgenden Bezeichner: alnum, alpha, blank, cntrl, digit, graph, lower, print, punct, space, upper, xdigit dann die betreffende Charakterklasse. Siehe ctype(3) für Details.


Für detailliertere Informationen siehe die man-page regex(7) oder, falls nicht vorhanden die man-page zu awk(1), welche lange Zeit auch als die Referenz für REs galt, oder flex(1) oder die Online-Dokumentation der Open Group.

Regular Examples

(x|y|z) ist äquivalent zu [xyz] und (a|b) ist äquivalent zu (b|a). Die RE (B|Dr)al{2} passt sowohl auf "Ball" als auch auf "Drall". Die RE ^#.* passt auf alle Zeilen, die mit einem '#' anfangen.

Ist die RE ^# äquivalent zur vorhergehenden? Zur reinen Mustersuche passen beide REs auf die selben Zeilen, der Unterschied kommt dann zu Tage, wenn man die gefundenen Muster weiterverarbeiten will. Erstere RE benennt die ganze Zeile, vom Beginn bis zum newline, zweitere benennt nur das Zeichen '#' am Anfang der Zeile.

Eine Gleitkommazahl wie 3.675E-15 kann man mit [[:digit:]]+\.[[:digit:]]*([eE][+-]?[[:digit:]]+)? beschreiben. Zu beachten ist der Backslash '\' vor dem Punkt, da jener eine Sonderbedeutung hat, die mit dem vorangestellten '\' unterbunden wird. Leider hat diese Beschreibung einen Nachteil: sie lässt zwar die Zahl 1. durch, verbietet aber die Zahl .1, also noch einmal: (([[:digit:]]+\.[[:digit:]]*)|(\.[[:digit:]]+))([eE][+-]?[[:digit:]]+)? Wie man sieht, werden REs schnell unübersichtlich. Das Chaos wird in Verbindung mit sed und bash perfekt, da sich noch viele lustige '\' und '/' hinzugesellen werden. Dazu aber später.

Grenzen von REs

Mit REs lassen sich nicht alle Zeichenketten beschreiben. Es ist zum Beispiel unmöglich ein System von balancierten Klammern zu beschreiben, auch ist die Menge {wcw | w ist ein String bestehend aus 'a's und 'b's} als RE nicht auszudrücken. Mehr zu REs kann man im 'Drachenbuch', Compilers - Principles, Techniques and Tools von Aho, Sethi und Ullman nachlesen.

sed und REs

sed verwendet Basic Regular Expressions, eine Art Untermenge der oben vorgestellten Erweiterten Regulären Ausdrücke. Einige Unterschiede sind:

  • Die Quantifikatoren "|", "+" und "?" sind normale Zeichen, und es gibt keine äquivalenten Operatoren dafür. GNU-sed kennt diese Operatoren, wenn sie durch einen vorangestellten Backslash "escaped" werden

  • Die geschwungenen Klammern sind normale Zeichen, und müssen mit Backslashes "escaped" werden, werden also als "\{" und "\}" geschrieben. Das selbe gilt für runde Klammern; die Zeichen, die durch "\(" und "\)" eingeschlossen werden, können später mit "\1" usw. dereferenziert werden

  • "^" ist ein normales Zeichen, wenn es nicht am Beginn einer Zeile oder eines Klammerausdrucks steht

  • "$" ist ein normales Zeichen, wenn es nicht am Ende einer Zeile oder eines Klammerausdrucks steht

  • "*" ist ein normales Zeichen am Beginn einer Zeile oder eines Klammerausdrucks