Regex

Aus Programmieren-Wiki
🚧 Diese Seite befindet sich in Bearbeitung 🚧

Ein Regex ist eine "regular expression", zu Deutsch "regulärer Ausdruck". Diese Art von Sprache werdet ihr auch in dem Modul Grundbegriffe der Informatik (GBI) kennenlernen (oder habt das bereits). Sie werden in der Vorlesung Programmieren zwar nicht explizit eingeführt, können allerdings trotzdem ein hilfreiches Tool sein.

Einen Regex selbst können wir uns als eine Art "Zusammensetzung aus Regeln" vorstellen, mit denen wir eine gegebene Zeichenkette nach einem Muster überprüfen können. Wenn ein Regex eine Zeichenkette "erkannt" hat, nennen wir das "match". Diesen match können wir mit der von Java bereitgestellten Methode "String.matches(regex)" als Boolean in einer Verzweigung behandeln.

Es ist also vergleichbar mit einem Lego-Bauset mit welchem wir für verschiedenste Problemstellungen, eigene Regex bilden können. Einige dieser "Bausteine" sind hier einmal aufgelistet:

Häufigkeiten von Zeichen

Im folgenden ist von einzelnen Zeichen die Rede, mit später eingeführten Gruppierungen gelten die hier vorgestellten Regeln dann auch für diese gruppierten Zeichen, also Zeichenketten.

  • * : Ein Zeichen muss beliebig oft vorkommen. a* würde also alle Zeichenketten matchen, die aus beliebig vielen, hintereinander stehenden, a bestehen. Hierbei ist es auch möglich, dass dieses Zeichen gar nicht vorkommt.
  • + : Ein Zeichen muss mindestens einmal vorkommen. a+ würde also genau jene Zeichenketten matchen, die aus mindestens einem, aber sonst beliebig vielen, a bestehen. Auch hier, müssen die a aneinanderhängend sein.
  • ? : Ein Zeichen kommt entweder gar nicht oder genau einmal vor. Wir prüfen damit also die Existenz eines Zeichens. a? prüft also ob das Zeichen ein a ist oder nichts.

Auswahl von Zeichen

  • | : Mit jeweils einem Zeichen links und rechts wird hiermit eine Auswahl bereitgestellt, welches der beiden Zeichen vorhanden sein soll. a | b sagt also aus, dass entweder ein a oder ein b vorhanden sein soll.
  • () : Hiermit stellen wir eine sogenannte "Capture Group" bereit. Mit ihr werden andere Regeln auf ganze Zeichenketten angewandt. Zum Beispiel (abc)+ Hier werden Zeichenketten die aus mindestens einmal der Reihenfolge abc bestehen. Also abc, abcabc, ... . Zu beachten ist, dass (a+b+c+) nicht dasselbe ist wie (abc)+, warum?
  • [] : Hier geht es jetzt tatsächlich um eine freie Auswahl von Zeichen. Alle Zeichen, die in den eckigen Klammern stehen werden gesucht, allerdings nur so oft wie angegeben. [abc] sucht also a, b oder c. Es ist sogesehen etwas wie eine erweiterte Form des Bar Zeichens |. Allerdings kann mit eckigen Klammern, anders wie dem Bar, keine Zeichenkette vorgegeben werden die existieren soll. Die richtige Wahl ist also wichtig.
  • - : Oder auch Range vereinfacht vor allem die Ausdrücke in eckigen Klammern. Hiermit können wir gleich eine ganze Menge an Buchstaben oder Zahlen definieren die Vorkommen sollen. Es wird Alphabetisch und Numerisch sortiert. Sprich: g-z enthält z.B. nicht a. Es ist also wichtig, welche Buchstaben und Zahlen definiert werden. Außerdem ist die Range case sensitive. Das heißt, Klein- und Großbuchstaben müssen seperat definiert werden (wenn sie denn beide benötigt werden). In diesem Fall gäbe es aber auch bessere Alternativen

Zusätzlich zu den oben genannten Regelzeichen gibt es auch noch zusätzliche "Tokens" von denen im folgenden ein paar, aber nicht alle, aufgelistet werden. Diese sollen uns ein wenig zur Hand gehen und Regexe etwas einfacher zu schreiben und lesen machen.

Tokens

  • . : Ein beliebiges Zeichen (außer Zeilenumbrüche \n)
  • \s : Ein "Whitespace" (Leerzeichen)
  • \d : Eineb beliebige Ziffer
  • \w : Ein beliebiger Buchstabe (groß oder klein) oder eine beliebige Ziffer
  • \W : *kein* Buchstabe oder Ziffer, also nur Sonderzeichen wie ., @, %, ...

In der Regel bedeutet ein kleiner Buchstabe, dass es vorkommen soll und der entsprechende Großbuchstabe, dass es nicht vorkommen soll.

Die eben vorgestellten Tokens lassen sich auch beliebig mit den anderen vorgestellten Regeln kombinieren:

(0|1)\d+ sucht eine Zeichenkette, deren erstes Zeichen eine 0 oder 1 ist, und mit mindestens einer weiteren Ziffer weitergeht.

In Java würden wir einen Regex wiefolgt implementieren.

Beispiel

String REGEX_NAME = "Hello .*";
[...]
if (input.matches(REGEX_NAME)) {
System.out.println("Found a match!");
} else {
System.out.println("The input did not contain a substring matching the given rule!");
}

Für input = "Hello John Smith" wäre die Ausgabe also "Found a match!".

Im allgemeinen ist die Seite hier sehr gut geeignet um Regexe zu testen und erstellen. Dort werden auch viel mehr Tokens und Regeln aufgeführt, die hier jetzt nicht genannt wurden, zur Erstellung von Regexen aber durchaus nützlich sein könnten.

Wichtig

Regexe sind zwar toll, sie sollten aber in maßen benutzt werden. Sie sollen nicht die Methoden der Java API zur Validierung von Eingaben ersetzen. D.h. Integer.parseInt() sollte nicht durch einen Codeblock mit [0-9]* ersetzt werden. Außerdem gelten Regexe als nicht trivial, da sie nicht Teil des Vorlesungsstoffes sind und sollten deshalb mit einem erklärenden Kommentar begleitet werden. Nicht eindeutige oder komplizierte Regexe ohne Kommentar geben in der Korrektur sonst Abzug. Da es schwer ist allgemein zu definieren, was trivial ist oder nicht, ist es empfohlen, alle Regexe mit einem kleinen Kommentar zu versehen.

Ein Beispiel für die eben genannte Richtlinie sind die "Error"-Patterns aus Artemis. <^Error: .*> bzw. <^(?!Error: ).*$> sind relatik klein und scheinen erst einmal unkompliziert. Allerdings würden diese Patterns ohne ein begleitendes Kommentar zu Abzug führen. Besser wäre also:

// This pattern checks for a string that starts with "Error: " followed by any string
String PATTERN = "Error . *";