Teil 05: Zeichenklassen
Zeichenklassen kann man sich so aehnlich wie Alternationen vorstellen, bloss fuer einzelne Zeichen statt fuer ganze Ausdruecke. Von der Ausdrucksmoeglichkeit sind sie theoretisch nicht unbedingt noetig wenn man Alternation und Unterausdruecke hat, aber in der Praxis sind sie ungeheuer praktisch. Ausserdem sind sie ein Standardfeature, das man in in allen RE-Varianten identisch wiederfindet.
Wenn wir nach ``Samstag'' oder ``Sonnabend'' suchen wollen, dann brauchen wir dafuer eine Alternation: `Samstag|Sonnabend'.
Wenn wir nach ``Maier'' oder ``Meier'' suchen wollten, dann koennen wir das ebenfalls mit einer Alternation machen: `Maier|Meier'. Hier ist die Abweichung der zwei Varianten jedoch nur gering. Den gemeinsamen Teil koennen wir darum auch nur einmal schreiben und einen Unterausdruck nutzen: `M(a|e)ier'.
Wenn nun alle Teilausdruecke der Alternation nur genau ein Zeichen sind, dann koennen wir stattdessen auch eine Zeichenklasse verwenden:
Code: Alles auswählen
M[ae]ier
Eine Zeichenklasse wird mit eckigen Klammern geschrieben, zwischen denen alle Zeichen aufgefuehrt werden fuer die die Zeichenklasse stehen kann. In diesem Beispiel kann die Zeichenklasse also entweder fuer `a' oder fuer `e' stehen.
Metazeichen
Innerhalb von Zeichenklassen werden fast alle Zeichen, also auch die normalen Metazeichen (wie Pipe und Klammern und auch das Escapezeichen Backslash!), literal interpretiert.
Speziell sind in Zeichenklassen nur wenige Zeichen, auf die ich nun nach und nach komme.
Die schliessende eckige Klammer (]). Diese markiert das Ende der Zeichenklasse. Wenn die schliessende eckige Klammer von der Zeichenklasse literal gematcht werden soll, dann muss sie als erstes Zeichen verwendet werden:
Code: Alles auswählen
[]abc]
Die schliessende eckige Klammer hat also an jeder Stelle einer Zeichenklasse eine Metabedeutung (naemlich die Zeichenklasse zu beenden), ausser als erstes Zeichen innerhalb der Zeichenklasse.
Negation
Zeichenklassen koennen eines was Alternationen nicht koennen, naemlich den Match invertieren. Eine Zeichenklasse kann man ausdruecken: Jedes Zeichen *ausser* den angegebenen. Dazu muss als erstes Zeichen in der Zeichenklasse ein Circumflex (Caret) stehen. Dieser negiert die Zeichenklasse. Die Zeichenklasse matcht dann alle Zeichen ausser die auf den Circumflex folgenden.
Eine Zeichenklasse, die alle Zeichen, ausser den Satzzeichen Punkt, Ausrufezeichen und Fragezeichen matcht sieht folgendermassen aus:
Code: Alles auswählen
[^.!?]
Diese Zeichenklasse matcht auf die Satzzeichen und den Circumflex:
Code: Alles auswählen
[.!?^]
Code: Alles auswählen
[.^!?]
Bereiche
Eine Zeichenklasse, die eine beliebige Ziffer matcht kann man noch einigermassen hinschreiben:
Code: Alles auswählen
[0123456789]
Code: Alles auswählen
[a-z]
1) 0-9 fuer die Ziffern
2) A-Z fuer die Grossbuchstaben
3) a-z fuer die Kleinbuchstaben
Wobei bei den Buchstaben nicht unbedingt eindeutig ist, ob Umlaute enthalten sein werden oder nicht. Solange man sich nur im Rahmen von US-ASCII bewegt, klappt das alles gut, darueber hinaus sollte man nicht zu genaue Erwartungen haben. Diese Ungenauigkeiten kann man in der Praxis meist problemlos in Kauf nehmen, angesichts der praktischen Bequemlichkeit von Bereichen in Zeichenklassen.
Will man sowohl Gross- als auch Kleinbuchstaben matchen, so muss man beide Bereiche separat angeben:
Code: Alles auswählen
[A-Za-z]
Ein Minuszeichen bildet immer dann einen Bereich, wenn es in einer Zeichenklasse zwischen zwei literalen Zeichen steht. In diesen Faellen ist es ein Metazeichen. Steht das Minuszeichen ganz am Anfang oder ganz am Ende, so kann es keinen Bereich aufspannen und steht dann literal fuer sich selbst.
Vordefinierte Bereiche
Da die Internationalisierung Zeichenklassenbereiche erschwert hat und weil man immer wieder bestimmte Bereiche braucht, die man ggf. auch nicht schnell mal hinschreiben kann (wie alle druckbaren Zeichen, beispielsweise), hat POSIX einige Zeichenklassenausdruecke eingefuehrt:
[:alnum:] alphanumerische Zeichen
[:alpha:] Buchstaben
[:blank:] Leerzeichen und Tab
[:cntrl:] Steuerzeichen
[:digit:] Ziffern
[:graph:] druckbare Zeichen ausser Whitespace
[:lower:] Kleinbuchstaben
[:print:] alle druckbaren Zeichen
[:punct:] Punktuationszeichen, Klammern, etc.
[:space:] Whitespace
[:upper:] Grossbuchstaben
[:xdigit:] Hexadezimalziffern
Jeder davon steht fuer eine Liste von Zeichen bzw. einen Bereich. So steht, vereinfacht gesagt, `[:lower:]' fuer `a-z'. Man achte hier auf die eckigen Klammern! Eine Zeichenklasse, die die Kleinbuchstaben matcht kann so aussehen:
Code: Alles auswählen
[a-z]
Code: Alles auswählen
[[:lower:]]
Code: Alles auswählen
[a-z0-9]
[[:lower:][:digit:]]
[[:lower:]0-9]
[01234[:lower:]5-9]
usw.
POSIX beschreibt noch weitere Spezialangaben fuer innerhalb von Zeichenklassen ([= =] und [. .]), aber die werden seltenst gebraucht und hier darum ausgelassen.
Reihenfolge
Bei der Reihenfolge innerhalb der Zeichenklasse sind die drei Zeichen mit Sonderbedeutung ^ - ] relevant. Der Circumflex hat nur an wirklich allererster Stelle seine Sonderbedeutung. Die schliessende eckige Klammer verliert ihre Sonderbedeutung als erstes Zeichen auch noch hinter dem Circumflex. Wenn also beides auftritt, dann muss der Circumflex zur Negation zuerst kommen. Das Minus verliert seine Sonderbedeutung als letztes Zeichen (wo es auch mit keinem anderen Sonderzeichen kollidieren kann). Oder, falls keine schliessende eckige Klammer vorhanden ist, als erstes Zeichen (ggf. nach einem Negations-Circumflex).
Aufgaben:
Schreibe Regulaere Ausdruecke, wenn moeglich, dann gerne verschiedene Varianten. Setzte sie mit egrep um und teste sie gegen selbst ausgedachten Input.
1) RE fuer eine Hexadezimalziffer.
2) RE fuer eine dreistellige Ganzzahl
3) RE fuer eine dreistellige Ganzzahl mit (Pflicht-)Vorzeichen.
4) RE fuer einen Euro-und-Cent-Betrag kleiner 10,-.
5) RE fuer die 31 Tage des Januars (zweistelliges Format mit fuehrender Null). Zwei Varianten.
6) RE fuer die 28 Tage des Februars (zweistelliges Format mit fuehrender Null). Zwei Varianten.
7) RE fuer ein beliebiges Zeichen, das kein Buchstabe ist.
RE fuer eine beliebige Ziffer. Drei verschiedene Varianten.
9) RE fuer ein Zeichen, das kein Circumflex (^) ist.
10) RE fuer eine Zeichenklasse, die nur einen Circumflex matcht.
11) RE fuer ein Minus oder eine eckige Klammer.
12) RE die alles ausser einer schliessenden eckigen Klammer oder einem Circumflex matcht.
13) Schreibe zwei verschiedene REs, die beide einen Backslash matchen.
14) Was matcht die Zeichenklasse `[A-z]' ausser Buchstaben sonst noch? (Zeichensatz: US-ASCII)
15) RE, die einen Tab matcht. Versuche mehrere Varianten zu finden.
16) Schreibe einen egrep-Ausdruck (nun auch mit Zeichenklassen), um die Schreibweisen Maier, Meier, Mayer, Meier und Myer zu matchen.