Java Reguläre Ausdrücke: Pattern Matching mit java.util.regex meistern
Einführung in Java Reguläre Ausdrücke
Java stellt das Paket java.util.regex für Pattern Matching mit regulären Ausdrücken bereit. Java reguläre Ausdrücke ähneln stark der Programmiersprache Perl und sind sehr einfach zu erlernen.
Ein regulärer Ausdruck ist eine spezielle Zeichenfolge, die hilft, andere Strings oder Mengen von Strings zu finden oder zu matchen, indem eine spezialisierte Syntax in einem Pattern verwendet wird. Sie können zum Suchen, Bearbeiten oder Manipulieren von Text und Daten eingesetzt werden.
Die drei Hauptklassen von java.util.regex
Das Paket java.util.regex besteht hauptsächlich aus den folgenden drei Klassen:
- Pattern Klasse – Ein Pattern-Objekt ist eine kompilierte Repräsentation eines regulären Ausdrucks. Die Pattern-Klasse bietet keine öffentlichen Konstruktoren. Um ein Pattern zu erstellen, muss man eine der öffentlichen statischen
compile()-Methoden aufrufen, die dann ein Pattern-Objekt zurückgeben. Diese Methoden akzeptieren einen regulären Ausdruck als erstes Argument. - Matcher Klasse – Ein Matcher-Objekt ist die Engine, die das Pattern interpretiert und Match-Operationen gegen einen Eingabe-String durchführt. Wie die Pattern-Klasse definiert auch Matcher keine öffentlichen Konstruktoren. Man erhält ein Matcher-Objekt, indem man die
matcher()-Methode auf einem Pattern-Objekt aufruft. - PatternSyntaxException – Ein PatternSyntaxException-Objekt ist eine unchecked Exception, die einen Syntaxfehler in einem regulären Ausdruck-Pattern anzeigt.
Capturing Groups (Erfassende Gruppen)
Erfassende Gruppen sind eine Möglichkeit, mehrere Zeichen als eine einzelne Einheit zu behandeln. Sie werden erstellt, indem die zu gruppierenden Zeichen in eine Reihe von Klammern gesetzt werden. Zum Beispiel erstellt der reguläre Ausdruck (dog) eine einzelne Gruppe, die die Buchstaben "d", "o" und "g" enthält.
Erfassende Gruppen werden nummeriert, indem man ihre öffnenden Klammern von links nach rechts zählt. Im Ausdruck ((A)(B(C))) gibt es beispielsweise vier solche Gruppen:
((A)(B(C)))(A)(B(C))(C)
Um herauszufinden, wie viele Gruppen in einem Ausdruck vorhanden sind, ruft man die groupCount-Methode auf einem Matcher-Objekt auf. Die Methode gibt einen int-Wert zurück, der die Anzahl der erfassenden Gruppen im Pattern des Matchers anzeigt.
Es gibt auch eine spezielle Gruppe, Gruppe 0, die immer den gesamten Ausdruck repräsentiert. Diese Gruppe ist in der von groupCount gemeldeten Gesamtzahl nicht enthalten.
Beispiel: Ziffernfolge aus alphanumerischem String extrahieren
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches {
public static void main(String args[]) {
// Zu durchsuchender String
String line = "This order was placed for QT3000! OK?";
String pattern = "(.*)(\\d+)(.*)";
// Pattern-Objekt erstellen
Pattern r = Pattern.compile(pattern);
// Matcher-Objekt erstellen
Matcher m = r.matcher(line);
if (m.find()) {
System.out.println("Found value: " + m.group(0));
System.out.println("Found value: " + m.group(1));
System.out.println("Found value: " + m.group(2));
} else {
System.out.println("NO MATCH");
}
}
}
Ausgabe:
Found value: This order was placed for QT3000! OK?
Found value: This order was placed for QT300
Found value: 0
Syntax Regulärer Ausdrücke in Java
Die folgende Tabelle listet die gesamte Metazeichen-Syntax für reguläre Ausdrücke auf, die in Java verfügbar sind:
| Subexpression | Beschreibung |
|---|---|
| ^ | Matcht den Zeilenanfang. |
| $ | Matcht das Zeilenende. |
| . | Matcht jedes einzelne Zeichen außer Zeilenumbruch. Mit der m-Option matcht es auch Zeilenumbrüche. |
| [...] | Matcht jedes einzelne Zeichen in den Klammern. |
| [^...] | Matcht jedes einzelne Zeichen, das nicht in den Klammern steht. |
| \A | Anfang des gesamten Strings. |
| \z | Ende des gesamten Strings. |
| \Z | Ende des gesamten Strings, außer einem erlaubten finalen Zeilenende. |
| re* | Matcht 0 oder mehr Vorkommen des vorangehenden Ausdrucks. |
| re+ | Matcht 1 oder mehr Vorkommen des vorangehenden Ausdrucks. |
| re? | Matcht 0 oder 1 Vorkommen des vorangehenden Ausdrucks. |
| re{ n} | Matcht genau n Vorkommen des vorangehenden Ausdrucks. |
| re{ n,} | Matcht n oder mehr Vorkommen des vorangehenden Ausdrucks. |
| re{ n, m} | Matcht mindestens n und höchstens m Vorkommen des vorangehenden Ausdrucks. |
| a| b | Matcht entweder a oder b. |
| (re) | Gruppiert reguläre Ausdrücke und merkt sich den gematchten Text. |
| (?: re) | Gruppiert reguläre Ausdrücke, ohne sich den gematchten Text zu merken. |
| (?> re) | Matcht das unabhängige Pattern ohne Backtracking. |
| \w | Matcht Wortzeichen (Buchstaben, Ziffern, Unterstrich). |
| \W | Matcht Nicht-Wortzeichen. |
| \s | Matcht Whitespace. Entspricht [\t\n\r\f]. |
| \S | Matcht Nicht-Whitespace. |
| \d | Matcht Ziffern. Entspricht [0-9]. |
| \D | Matcht Nicht-Ziffern. |
| \A | Matcht den Stringanfang. |
| \Z | Matcht das Stringende. Falls ein Zeilenumbruch existiert, matcht es direkt davor. |
| \z | Matcht das Stringende. |
| \G | Matcht den Punkt, wo der letzte Match endete. |
| \n | Back-Reference auf Erfassungsgruppe Nummer "n". |
| \b | Matcht Wortgrenzen (außerhalb von Klammern). Matcht Backspace (0x08) innerhalb von Klammern. |
| \B | Matcht Nicht-Wortgrenzen. |
| \n, \t, etc. | Matcht Zeilenumbrüche, Wagenrückläufe, Tabs, etc. |
| \Q | Escaped (quotet) alle Zeichen bis \E. |
| \E | Beendet das Quoting, das mit \Q begonnen wurde. |
Methoden der Matcher-Klasse
Index-Methoden
Index-Methoden liefern nützliche Indexwerte, die präzise anzeigen, wo der Match im Eingabe-String gefunden wurde:
| Nr. | Methode & Beschreibung |
|---|---|
| 1 | public int start() – Gibt den Startindex des vorherigen Matches zurück. |
| 2 | public int start(int group) – Gibt den Startindex der Teilfolge zurück, die von der angegebenen Gruppe beim vorherigen Match erfasst wurde. |
| 3 | public int end() – Gibt den Offset nach dem letzten gematchten Zeichen zurück. |
| 4 | public int end(int group) – Gibt den Offset nach dem letzten Zeichen der Teilfolge zurück, die von der angegebenen Gruppe beim vorherigen Match erfasst wurde. |
Study-Methoden (Prüfmethoden)
Study-Methoden prüfen den Eingabe-String und geben einen Boolean-Wert zurück, der angibt, ob das Pattern gefunden wurde:
| Nr. | Methode & Beschreibung |
|---|---|
| 1 | public boolean lookingAt() – Versucht, die Eingabesequenz ab dem Anfang der Region gegen das Pattern zu matchen. |
| 2 | public boolean find() – Versucht, die nächste Teilfolge der Eingabesequenz zu finden, die das Pattern matcht. |
| 3 | public boolean find(int start) – Setzt diesen Matcher zurück und versucht dann, die nächste Teilfolge zu finden, die das Pattern matcht, beginnend am angegebenen Index. |
| 4 | public boolean matches() – Versucht, die gesamte Region gegen das Pattern zu matchen. |
Ersetzungsmethoden (Replacement Methods)
Ersetzungsmethoden sind nützlich, um Text in einem Eingabe-String zu ersetzen:
| Nr. | Methode & Beschreibung |
|---|---|
| 1 | public Matcher appendReplacement(StringBuffer sb, String replacement) – Implementiert einen nicht-terminalen Append-and-Replace-Schritt. |
| 2 | public StringBuffer appendTail(StringBuffer sb) – Implementiert einen terminalen Append-and-Replace-Schritt. |
| 3 | public String replaceAll(String replacement) – Ersetzt jede Teilfolge der Eingabesequenz, die das Pattern matcht, mit dem gegebenen Ersetzungsstring. |
| 4 | public String replaceFirst(String replacement) – Ersetzt die erste Teilfolge der Eingabesequenz, die das Pattern matcht, mit dem gegebenen Ersetzungsstring. |
| 5 | public static String quoteReplacement(String s) – Gibt einen literalen Ersetzungsstring für den angegebenen String zurück. Diese Methode erzeugt einen String, der als literaler Ersetzung s in der appendReplacement-Methode der Matcher-Klasse funktioniert. |
Die start- und end-Methoden – Beispiel
Das folgende Beispiel zählt, wie oft das Wort "cat" im Eingabe-String vorkommt:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches {
private static final String REGEX = "\\bcat\\b";
private static final String INPUT = "cat cat cat cattie cat";
public static void main(String args[]) {
Pattern p = Pattern.compile(REGEX);
Matcher m = p.matcher(INPUT);
int count = 0;
while (m.find()) {
count++;
System.out.println("Match number " + count);
System.out.println("start(): " + m.start());
System.out.println("end(): " + m.end());
}
}
}
Ausgabe:
Match number 1 start(): 0 end(): 3
Match number 2 start(): 4 end(): 7
Match number 3 start(): 8 end(): 11
Match number 4 start(): 19 end(): 22
Man sieht, dass dieses Beispiel Wortgrenzen verwendet, um sicherzustellen, dass die Buchstaben "c", "a", "t" nicht lediglich ein Teilstring in einem längeren Wort sind. Es liefert auch nützliche Informationen darüber, wo im Eingabe-String der Match aufgetreten ist.
Die start-Methode gibt den Startindex der Teilfolge zurück, die von der gegebenen Gruppe während der vorherigen Match-Operation erfasst wurde, und end gibt den Index des letzten gematchten Zeichens plus eins zurück.
Die matches- und lookingAt-Methoden
Die matches- und lookingAt-Methoden versuchen beide, eine Eingabesequenz gegen ein Pattern zu matchen. Der Unterschied ist jedoch, dass matches die gesamte Eingabesequenz matchen muss, während lookingAt dies nicht muss.
Beide Methoden beginnen immer am Anfang des Eingabe-Strings. Hier ist ein Beispiel, das die Funktionalität erklärt:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches {
private static final String REGEX = "foo";
private static final String INPUT = "fooooooooooooooooo";
private static Pattern pattern;
private static Matcher matcher;
public static void main(String args[]) {
pattern = Pattern.compile(REGEX);
matcher = pattern.matcher(INPUT);
System.out.println("Current REGEX is: " + REGEX);
System.out.println("Current INPUT is: " + INPUT);
System.out.println("lookingAt(): " + matcher.lookingAt());
System.out.println("matches(): " + matcher.matches());
}
}
Ausgabe:
Current REGEX is: foo
Current INPUT is: fooooooooooooooooo
lookingAt(): true
matches(): false
Die replaceFirst- und replaceAll-Methoden
Die replaceFirst- und replaceAll-Methoden ersetzen den Text, der einen gegebenen regulären Ausdruck matcht. Wie ihre Namen andeuten, ersetzt replaceFirst das erste Vorkommen, und replaceAll ersetzt alle Vorkommen.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches {
private static String REGEX = "dog";
private static String INPUT = "The dog says meow. " + "All dogs say meow.";
private static String REPLACE = "cat";
public static void main(String[] args) {
Pattern p = Pattern.compile(REGEX);
Matcher m = p.matcher(INPUT);
INPUT = m.replaceAll(REPLACE);
System.out.println(INPUT);
}
}
Ausgabe:
The cat says meow. All cats say meow.
Die appendReplacement- und appendTail-Methoden
Die Matcher-Klasse stellt auch appendReplacement und appendTail für Textersetzungen bereit.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches {
private static String REGEX = "a*b";
private static String INPUT = "aabfooaabfooabfoob";
private static String REPLACE = "-";
public static void main(String[] args) {
Pattern p = Pattern.compile(REGEX);
Matcher m = p.matcher(INPUT);
StringBuffer sb = new StringBuffer();
while (m.find()) {
m.appendReplacement(sb, REPLACE);
}
m.appendTail(sb);
System.out.println(sb.toString());
}
}
Ausgabe:
-foo-foo-foo-
PatternSyntaxException Klassenmethoden
Eine PatternSyntaxException ist eine unchecked Exception, die einen Syntaxfehler in einem regulären Ausdruck-Pattern anzeigt. Die PatternSyntaxException-Klasse bietet die folgenden Methoden, um zu ermitteln, was schiefgelaufen ist:
| Nr. | Methode & Beschreibung |
|---|---|
| 1 | public String getDescription() – Ruft die Beschreibung des Fehlers ab. |
| 2 | public int getIndex() – Ruft den Fehlerindex ab. |
| 3 | public String getPattern() – Ruft das fehlerhafte reguläre Ausdruck-Pattern ab. |
| 4 | public String getMessage() – Gibt einen mehrzeiligen String zurück, der die Beschreibung des Syntaxfehlers und seinen Index, das fehlerhafte Pattern und eine visuelle Anzeige des Fehlerindex innerhalb des Patterns enthält. |
Java
- C# Ausdrücke, Anweisungen & Blöcke: Umfassender Leitfaden mit Beispielen
- Java Operatoren meistern: Typen, Syntax und praktische Beispiele
- Java Ausdrücke, Anweisungen und Blöcke verstehen
- Java Kommentare: Typen, Verwendung und Best Practices
- Java Enhanced For-Schleife meistern: Syntax, Beispiele und Best Practices
- Java Strings meistern: Erstellung, Methoden und Best Practices
- Java-Schnittstellen meistern: Konzepte, Implementierung und Best Practices
- Java Try-With-Resources meistern: Automatisches Ressourcenmanagement erklärt
- Java Annotations erklärt: Typen, Platzierung und praktische Beispiele
- Java Assertions: Praktischer Leitfaden zur Fehlererkennung und Code-Reliabilität