Wenn Google etwas nicht finden kann, fragen sie Jack Bauer. ("Fakten über Jack Bauer") Inhalt Empfehlenswerte Referenzen...1 0 Wozu reguläre Ausdrücke?...1 1 Die Elemente regulärer Ausdrücke...2 2 Ein einfaches Beispiel...3 Welche dieser Worte sind in der vom gegebenen regulären Ausdruck erzeugten Sprache enthalten?...3 Lösung...4 3 Ein anspruchsvolleres Beispiel...4 Welcher reguläre Ausdruck erzeugt die vorgegebene Sprache?...4 Lösung...5 4 Aufgaben to go...5 Empfehlenswerte Referenzen [1] RegEx Coach(http://weitz.de/regex-coach) Tool zur Verifikation von regulären Ausdrücken unter Eingabe von Testwörtern [2] Uwe Schöning "Theoretische Informatik kurzgefasst", Kapitel "1.2.3 Reguläre Ausdrücke" [3] regex Tester (http://www.regex-tester.de) ein online Testprogramm für reguläre Ausdrücke 0 Wozu reguläre Ausdrücke? Reguläre Ausdrücke können genau die Klasse der regulären Sprachen darstellen. Zum Beweis siehe [2]. Das heisst z. B.: für alles was man mit einem endlichen Automaten darstellen kann, kann man auch einen regulären Ausdruck angeben und andersherum. Es fragt sich nur, was einfacher ist. Im Rahmen der Vorlesung "Compilerbau" werden reguläre Ausdrücke verwendet, um rekursiv die zulässigen Konstrukte für die Syntax einer Computersprache zu definieren. Dadurch kommen auch mächtige Computersprachen mit erstaunlich wenigen Regeldefinitionen aus. Müßte man aber alle gültigen Konstruktionen für Regeln explizit angeben (also ohne reguläre Ausdrücke), wären enorm viel mehr Definitionen notwendig, worunter die Übersicht nicht unerheblich leiden würde. Die Computersprache SQL lässt zu, dass mit regulären Ausdrücken nach Daten gesucht wird. Das ermöglicht ziemlich kompakte Datenbankanfragen. Im Rahmen der Vorlesung "Datenbanken" wird das noch viel eingehender behandelt. Seite 1 / 6
1 Die Elemente regulärer Ausdrücke Seien im Folgenden die Zeichen R und S induktiv selbst reguläre Ausdrücke, sowie 'a', 'b' und 'c' beliebige Zeichen des zulässigen Alphabets. Wenn nichts weiter angegeben ist, entspricht das Alphabet dem ASCII-Zeichensatz. x und y sind beliebige natürliche Zahlen. Die doppelten Hochkommas gehören im folgenden jeweils nicht zum regulären Ausdruck, sondern zeigen lediglich den Beginn und das Ende desselben an. "" : leeres Wort. Auch das leere Wort ist ein zulässiger regulärer Ausdruck. Wiederholungen von regulären Ausdrücken. "R{x}" : genau x-fache Wiederholung von R. "R{x,}" : mindestens x-fache Wiederholung von R. "R{x,y}" : mindestens x-, aber höchstens y-fache Wiederholung von R "R*" : ("Kleen'scher Stern") beliebige Wiederholung von R. Entspricht dem Ausdruck "R{0,}". "R+" : mindestens einmalige Wiederholung von R. Entspricht dem Ausdruck "R{1,}". "R?" : optionale einmalige Wiederholung von R. Entspricht dem Ausdruck "R{0,1}". "RS" : reguläre Ausdrücke werden automatisch konkateniert ohne dass ein spezieller Konkatenationsoperator aufgeführt werden muss. Durch die Konkatenation folgt auf die Erkennung des Ausdrucks R die Erkennung des Ausdrucks S. "." : ("Wild Card") Platzhalter für ein beliebiges Zeichen des Alphabets. "R$" : nach Erkennung des Ausdrucks R muss das Wort zu Ende sein. "^R" : der Beginn des Wortes muss durch den Ausdruck R erkannt werden. "[abc]" : ein einzelnes beliebiges Zeichen aus der Liste der zwischen den eckigen Klammern aufgeführten Zeichen. "[a-c]" : ein einzelnes beliebiges Zeichen aus dem Bereich der Zeichen zwischen 'a' und 'c' (einschließlich diesen). "[^abc]": ("Negation") ein beliebiges Zeichen aus dem Alphabet, das nicht einem der in der Liste der zwischen '^' und ']' aufgeführten Zeichen entspricht. "R S": alternative Auswahl von entweder dem Ausdruck R oder dem Ausdruck S. "(R)": durch die Klammerung wird der Ausdruck R zu einer Einheit zusammengefasst. Ein nachfolgender Operator wie z. B. '*' oder '+' wirkt sich dann auf den gesamten Ausdruck R aus. "a" : Beliebige Zeichen des Alphabets, die nicht Teil der oben genannten Syntax sind, werden im regulären Ausdruck "einfach so" notiert. Insbesondere sind einzelne Anführungsstriche nicht notwendig, für einzelne Zeichen des Alphabets aber zulässig. Seite 2 / 6
Wenn Zeichen der Syntax (also z. B.: '(', ')', '[', ']', '^' oder '*') in Wörtern der Sprache erlaubt sein sollen, müssen diese Zeichen maskiert werden, was durch ein vorangestelltes Backslash (also ein '\') erfolgt. Wenn in einem Wort z. B. ein Fragezeichen erlaubt sein soll, muss also in dem regulären Ausdruck an der entsprechenden Stelle "\?" stehen. ' ' : Leerzeichen müssen durch Angabe von einzelnen Hochkommas explizit angegeben werden. Alle Leerzeichen in regulären Ausdrücken, die nicht in einzelne Hochkommas gefasst werden, werden ignoriert. Doppelte Hochkommas dienen dem Konkatenieren von Zeichen des Alphabets. Statt z. B. 'a' 'b' 'c' zu schreiben, kann man auch "abc" schreiben. Achtung: Diese Syntaxregeln weichen evtl. von denen aus dem Skript leicht ab. In der Prüfung unbedingt die Syntax des Skripts einhalten! Leider gibt es in der Praxis immer wieder Unterschiede in den Implementierungen der Regeln. Da hilft meist nur das genaue Lesen der Dokumentation (die hoffentlich vorliegt). 2 Ein einfaches Beispiel Welche dieser Worte sind in der vom gegebenen regulären Ausdruck erzeugten Sprache enthalten? ( [ 0 9 ] + [ \* \+ / \- ] [ 0 9 ] + ) * = [ 0 3 ] + (a) "3-2=1" (b) "0/0=2007" (c) "0 9+0 9=0" (d) "0 99+99 0=1" (e) "" (f) "1001+1001=2002" (g) "=0" (h) "99+1=" (i) "77+=77" (j) "13-33==1333" Seite 3 / 6
. Lösung (a) Ja. (b) Nein. Das Literal '7' ist rechts neben dem '=' nicht zugelassen. (c) Nein. Zwar kann der Teil links vom '=' beliebig wiederholt werden, aber dann müssen die Zahlen "mittendrin" aus mindestens zwei Ziffern bestehen. (d) Ja. (e) Nein. Ein zulässiges Wort muss mindestens aus '=' und einer nachfolgenden Ziffer zwischen 0 und 3 bestehen. (f) Ja. (g) Ja. (h) Nein. Nach dem '=' muss noch mindestens eine Ziffer zwischen 0 und 3 folgen. (i) Nein. Wenn auf der linken Seite etwas steht, muss nach dem Operator noch eine mindestens einstellige Zahl vor dem '=' folgen. (j) Nein. In zulässigen Wörtern muss genau ein '=' vorkommen und zwar genau vor der Zahl ganz rechts. 3 Ein anspruchsvolleres Beispiel Welcher reguläre Ausdruck erzeugt die vorgegebene Sprache? Es soll ein Erkennungsmuster für ein spezielles CSV-Format erstellt werden. CSV steht für "comma separated values", also Werte, die durch Kommas getrennt werden. In der EDV wird ein solches Datenformat oft für den pragmatischen Datenaustausch zwischen Applikationen verwendet. In diesem speziellen Szenario gelten folgende Vorschriften: Am Beginn der Datei steht genau einmal die Zeichenfolge "csv", so dass ein lesendes Programm weiss, dass es sich um eine CSV-Datei handelt. Werte sind Zahlenfolgen von einer Länge zwischen ein und zehn Ziffern. Führende Nullen sind nicht zulässig, der Wert "0" (bestehend aus einer einzelnen Ziffer '0') aber schon. Nach jedem Wert muss ein Komma (',') folgen, außer nach dem letzten. Nach dem letzten Wert darf kein ',' stehen. Vor dem ersten Wert der Datei muss genau einmal ein '{' stehen. Nach dem letzten Wert der Datei muss genau einmal ein '}' stehen. Zwischen Werten und Kommas sind optional auch Zeilenumbrüche erlaubt. Dies entspricht dem ASCII-Zeichen '\n'. Eine Datei kann auch leer sein (dann fehlen auch die Kennung "csv" sowie die geschweiften Klammern). Seite 4 / 6
. Lösung Wie geht man an so eine Aufgabe heran? Man kann z. B. diese Überlegungen anstellen: Da die Datei auch leer sein darf, ist also das leere Wort erlaubt. Der gesamte resultierende reguläre Ausdruck muss also von einer " ( )? "-Konstruktion eingefasst sein. Innerhalb der " ( )? "-Konstruktion beginnt der Ausdruck mit "csv". Danach muss ein '{' folgen und am Ende ein '}'. Diese beiden Zeichen müssen mit einem vorangestellten \ (=Backslash) maskiert werden, damit sie als ASCII-Zeichen erkannt werden und nicht als Teil der Syntax des regulären Ausdrucks. Damit haben wir als Zwischenschritt soweit mal den Ausdruck: " ( csv \{ \} )? " Jetzt müssen noch irgendwie Werte erlaubt sein. Wie sieht ein zulässiger Wert überhaupt aus? Führende Nullen werden dadurch ausgeschlossen, dass als erste Ziffer nur eine zwischen 1 und 9 zugelassen wird und der Wert "0" als alternativer Fall eingebaut wird. Allerdings muss nach der ersten Ziffer auch wieder die Ziffer 0 zugelassen werden. Die Bauweise zulässiger Werte ist also diese: " ( 0 [ 1 9 ] [ 0 9 ] { 0, 9 } ) " Wenn die Datei nicht leer ist, müssen auch Werte zwischen den geschweiften Klammern aufgeführt werden. Wenn allerdings nur ein einzelner Wert enthalten ist, darf auch kein Komma vorkommen. D. h. eine einmalige Aufführung des Wertes ist innerhalb der geschweiften Klammern zwingend und bei jeder weiteren Aufführung eines Wertes muss zuerst ein Komma aufgeführt werden. Außerdem können diese "weiteren Aufführungen von Werten" zwischen 0 und beliebig oft auftauchen. Insgesamt ergibt das als Ausdruck zwischen den geschweiften Klammern: " ( 0 [ 1 9 ] [ 0 9 ] { 0, 9 } ) ( ',' ( 0 [ 1 9 ] [ 0 9 ] { 0, 9 } ) ) * " Die optionalen Zeilenumbrüche müssen auch berücksichtigt werden. Sie dürfen nur zwischen Werten und den trennenden Kommas stehen, also müssen sie auch genau da eingebaut werden: " ( 0 [ 1 9 ] [ 0 9 ] { 0, 9 } ) ( '\n'? ',' '\n'? ( 0 [ 1 9 ] [ 0 9 ] { 0, 9 } ) ) * " Zuletzt muss noch der Ausdruck für Werte in den oben zusammengebauten Ausdruck für die "Gesamtdatei" zwischen die geschweiften Klammern eingebastelt werden und fertig ist das Ergebnis: " ( csv \{ ( 0 [ 1 9 ] [ 0 9 ] { 0, 9 } ) ( '\n'? ',' '\n'? ( 0 [ 1 9 ] [ 0 9 ] { 0, 9 } ) ) * \} )? " Seite 5 / 6
4 Aufgaben to go 1. Erstelle einen regulären Ausdruck, der einfache deutsche Sätze erkennt. Dabei gelten folgende Regeln: Das Alphabet besteht aus der Menge {'Prädikat', 'Substantiv', 'Verb', '.', 'und', 'oder', ','} Sätze müssen aus der Abfolge "Subjekt Verb Objekt" bestehen. Ein Subjekt besteht aus einem optionalen Prädikat und einem nachfolgenden Substantiv. Ebenso besteht ein Objekt aus einem optionalen Prädikat und einem nachfolgenden Substantiv. Nach einem Satz kommt entweder eine Konjunktion und dann ein weiterer Satz oder ein Punkt (also das Literal '.'). Als Konjunktion ist nur eines der Literale 'und', 'oder' oder ',' erlaubt. 2. Erstelle über dem Alphabet {'1', '2', '3'} einen regulären Ausdruck, der alle dreistelligen Wörter erkennt, die nicht einem dieser drei Wörter entsprechen: "123" "321" "222" Seite 6 / 6