4.6 Reguläre Ausdrücke 

Mit dem Paket java.util.regex lässt sich mithilfe der Klassen Matcher und Pattern eine Zeichenkette gegen ein Muster prüfen. Mit dieser leistungsfähigen Implementierung lässt sich die Funktionalität von Unix-Dienstprogrammen wie awk, sed, emacs, perl oder grep prinzipiell nachbilden.
4.6.1 Die Klassen Pattern und Matcher 

Im Prinzip besteht das Erkennen immer aus dem Aufbau eines regulären Ausdrucks und der Prüfung über die Klasse String oder Pattern:
Listing 4.6 AHrefRegularExpression.java, main()
String url = "<a href=\"www.tutego.com\">"; boolean b = String.matches( "<a href=.*>", url ); // true
Gleichwertig mit String.matches() ist Pattern.matches().
Der Punkt im regulären Ausdruck steht für ein beliebiges Zeichen, und der folgende Stern erlaubt wahllos viele beliebige Zeichen. Ein – hier nicht benutztes – vorgestelltes »\« maskiert das folgende Zeichen aus.
Regeln für reguläre Ausdrücke
Für reguläre Ausdrücke existieren eine ganze Menge von Regeln. Wichtige Quantifizierer für eine Zeichenkette X sind:
X? |
X kommt einmal oder keinmal vor. |
X* |
X kommt keinmal oder beliebig oft vor. |
X+ |
X kommt einmal oder beliebig oft vor. |
Die Bestandteile lassen sich zu Zeichenklassen zusammenfassen:
[aeiuo] |
Zeichen a, e, i, o oder u |
[^aeiuo] |
Nicht die Zeichen a, e, i, o, u |
[0-9a-fA-F] |
Zeichen 0, 1, 2, ..., 9 oder Groß-/Klein-Buchstaben a, b, c, d, e, f |
Daneben gibt es vordefinierte Zeichenklassen. Die wichtigsten sind:
. |
Jedes Zeichen |
\d |
Ziffer: [0-9] |
\D |
Keine Ziffer: [^0-9] bzw. [^\d] |
\s |
Weißraum: [ \t\n\x0B\f\r] |
\S |
Kein Weißraum: [^\s] |
\w |
Wortzeichen: [a-zA-Z0-9] |
\W |
Kein Wortzeichen: [^\w] |
\p{Blank} |
Leerzeichen oder Tab: [ \t] |
\p{Lower}, \p{Upper} |
Klein-/Großbuchstabe: [a-z] bzw. [A-Z] |
\p{Punct} |
Punkt-Zeichen: !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ |
\p{Graph} |
Sichtbares Zeichen: [\p{Alnum}\p{Punct}] |
\p{Print} |
Druckbare Zeichen: [\p{Graph}] |
Bei den Wortzeichen handelt es sich standardmäßig um die ASCII-Zeichen und nicht um deutsche Zeichen mit unseren Umlauten oder allgemeine Unicode-Zeichen. Eine umfassende Übersicht liefert die API-Dokumentation der Klasse java.util.regex.Pattern.
Die Pattern-API
Die einzelne Zeile lässt sich weiter zerlegen, denn String.matches() beziehungsweise Pattern.matches() ist nur eine Abkürzung für die Übersetzung eines Patterns und Anwendung von matches():
Pattern p = Pattern.compile( "<a href=.*>" ); Matcher m = p.matcher( "<a href=\"tutego.com\">" ); boolean b = m.matches();
static Pattern p = Pattern.compile( "[\\w|-]+@\\w[\\w|-]*\\.[a-z]{2,3}" ); |
final class java.util.regex.Pattern
implements Serializable |
- static Pattern compile( String regex ) Übersetzt den regulären Ausdruck in ein Pattern-Objekt.
- static Pattern compile( String regex, int flags ) Übersetzt den regulären Ausdruck in ein Pattern-Objekt mit Flags. Als Flags sind CASE_INSENSITIVE, MULTILINE, DOTALL, UNICODE_CASE und CANON_EQ erlaubt.
- int flags() Liefert die Flags, nach denen geprüft wird.
- Matcher matcher( CharSequence input ) Liefert ein Matcher-Objekt, das prüft.
- static boolean matches( String regex, CharSequence input ) Liefert true, wenn der reguläre Ausdruck regex auf die Eingabe passt.
- String pattern() Liefert den regulären Ausdruck, den das Pattern repräsentiert.
4.6.2 Mit MatchResult alle Ergebnisse einsammeln 

Die Schnittstelle java.util.regex.MatchResult deklariert Operationen, die Zugriff auf das Ergebnis (String, Start-, Endposition, Anzahl Gruppen) eines Matches ermöglichen. Ein Matcher-Objekt wird dafür mit toMatchResult() nach dem MatchResult-Objekt gefragt.
Ein einfaches Beispiel verdeutlicht die Arbeitsweise: Die eigene Utility-Funktion findMatches() soll für ein Muster und eine Zeichenkette alle Ergebnisse zurückliefern.
Listing 4.7 MatchResultDemo.java, Teil 1
public static Iterable<MatchResult> findMatches( String pattern, CharSequence s ) { List<MatchResult> results = new ArrayList<MatchResult>(); for ( Matcher m = Pattern.compile(pattern).matcher(s); m.find(); ) results.add( m.toMatchResult() ); return results; }
Die Methode liefert ein einfaches Iterable zurück, was in unserem Beispiel ausreicht, um die Funktion auf der rechten Seite des Doppelpunktes vom erweiterten for nutzen zu können. Vor dem Schleifendurchlauf übersetzt compile() den Muster-String in ein Pattern-Objekt und matcher() gibt Zugang zum konkreten Mustererkenner, also Matcher-Objekt. Die Bedingung der Schleife ist so, dass pro Durchlauf ein Muster erkannt wird. Im Rumpf der Schleife sammelt die Ergebnisliste die MatchResult-Objekte, welche die Funddaten repräsentieren. Nach Ablauf der Schleife liefert die Methode die gesammelten Objekte zurück.
Ein paar Programmzeilen zeigen schnell die Möglichkeiten. Ein einfaches Muster soll für ISBN-10-Nummern stehen – ohne Leerzeichen oder Bindestriche.
Listing 4.8 MatchResultDemo.java, Teil 2
String pattern = "\\d{9,10}[\\d|x|X]"; String s = "Insel: 3898425266, Reguläre Ausdrücke: 3897213494"; for ( MatchResult r : findMatches( pattern, s ) ) System.out.println( r.group() + " von " + r.start() + " bis " + r.end() );
Das Ergebnis auf der Konsole ist:
3898425266 von 7 bis 17 3897213494 von 39 bis 49
Die Informationen in einem MatchResult entsprechen also einem Zustand eines Matcher während des Parsens, genauer gesagt nach dem Erkennen einer Zeichenfolge. Daher implementiert auch die Klasse Matcher die Schnittstelle MatchResult.