Einführung in reguläre Ausdrücke in Java
Eine Einführung in reguläre Ausdrücke in Java mit dem Paket java.util.regex.
Ein regulärer Ausdruck (Regex) ist ein kompaktes Muster, das eine Menge von Zeichenketten beschreibt. In Java verwandelt das Paket java.util.regex diese Muster in eine kleine, schnelle Matching-Engine, die auf beliebigen Text angewendet werden kann — um Eingaben zu validieren, Teilzeichenketten zu suchen, Felder zu extrahieren oder Inhalte umzuschreiben. Dieses Kapitel legt die Grundlagen, bevor Sie eigene Muster schreiben.
Was ein regulärer Ausdruck ist
Ein Regex ist nur eine Zeichenkette in einer speziellen Syntax, aber Java interpretiert ihn nicht bei jeder Verwendung Zeichen für Zeichen. Stattdessen kompilieren Sie das Muster einmalig in ein Pattern-Objekt und wenden es dann über einen Matcher auf Eingaben an. Die kompilierte Form ist eine effiziente Zustandsmaschine, daher ist die Wiederverwendung eines Pattern für viele Eingaben viel günstiger als wiederholtes Kompilieren.
Muster beschreiben Strukturen: ein Literal wie cat passt genau auf diese Buchstaben, während Metazeichen Formen beschreiben — \d steht für eine beliebige Ziffer, + bedeutet „ein oder mehrmals", . bedeutet „ein beliebiges Zeichen". Kombiniert man sie, kann man Telefonnummern, E-Mail-Adressen oder Log-Zeilen in einer einzigen Codezeile beschreiben.
import java.util.regex.Pattern;
public class FirstPattern {
public static void main(String[] args) {
// Compile the pattern once; reuse the result.
Pattern digits = Pattern.compile("\\d+");
System.out.println(digits.matcher("abc123").find()); // true
System.out.println(digits.matcher("hello").find()); // false
}
}Beachten Sie den doppelten Backslash: \d im Regex muss als \\d in einem Java-String-Literal geschrieben werden, da der Java-Compiler einen Backslash zuerst verarbeitet.
Pattern und Matcher
Zwei Klassen erledigen fast die gesamte Arbeit. Pattern ist das kompilierte, wiederverwendbare, thread-sichere Blueprint. Matcher ist die zustandsbehaftete Engine, die diesen Blueprint auf eine bestimmte Eingabe anwendet — sie verfolgt, wo Sie sich im Text befinden, welche Gruppen erfasst wurden und wo das letzte Match endete. Erstellen Sie für jede Eingabe einen neuen Matcher; teilen Sie niemals einen über Threads hinweg.
| Typ | Rolle |
|---|---|
Pattern | Das kompilierte Muster. Unveränderlich, thread-sicher, wiederverwendbar. |
Matcher | Wendet ein Pattern auf eine Eingabe an. Hält den Match-Zustand. |
Pattern.compile(regex) | Erstellt ein Pattern aus einem Regex-String. |
pattern.matcher(input) | Gibt einen Matcher zurück, der an diese Eingabe gebunden ist. |
String.matches(regex) | Einmalige Hilfsmethode, die kompiliert und vollständig matcht in einem einzigen Aufruf. |
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PatternAndMatcher {
public static void main(String[] args) {
Pattern p = Pattern.compile("\\w+@\\w+\\.\\w+");
Matcher m = p.matcher("ping me at [email protected] please");
if (m.find()) {
System.out.println("Found email: " + m.group());
}
}
}find() vs matches()
Der häufigste Anfängerfehler ist die Verwechslung der beiden Methoden zum Ausführen eines Musters. matches() erfordert, dass die gesamte Eingabe vom Anfang bis zum Ende mit dem Muster übereinstimmt. find() sucht nach einem beliebigen Teilstring, der passt, und kann wiederholt aufgerufen werden, um alle Vorkommen zu durchlaufen. lookingAt() liegt dazwischen: Es verankert am Anfang, erfordert aber keine Übereinstimmung bis zum Ende.
| Methode | Am Anfang verankert? | Muss bis zum Ende passen? | Wiederholbar? |
|---|---|---|---|
matches() | ja | ja | nein |
lookingAt() | ja | nein | nein |
find() | nein | nein | ja |
import java.util.regex.Pattern;
public class FindVsMatches {
public static void main(String[] args) {
Pattern p = Pattern.compile("\\d+");
System.out.println(p.matcher("42").matches()); // true (whole input)
System.out.println(p.matcher("age 42").matches()); // false (extra text)
System.out.println(p.matcher("age 42").find()); // true (substring)
System.out.println(p.matcher("age 42").lookingAt()); // false (no digit at start)
}
}Häufige Syntax als Grundlage
Die meisten realen Muster werden aus einem kleinen Vokabular von Bausteinen zusammengesetzt: Zeichenklassen, vordefinierte Abkürzungen, Quantifikatoren und Anker. Das Erlernen dieser Elemente bringt Sie einen großen Schritt vorwärts. Jedes Konstrukt hat ein eigenes Kapitel — siehe Regex-Syntax, Zeichenklassen und Quantifikatoren für alle Details.
| Konstrukt | Bedeutung | Beispiel |
|---|---|---|
. | Ein beliebiges einzelnes Zeichen (außer Zeilenumbruch) | a.c passt auf abc, axc |
\d \w \s | Ziffer, Wortzeichen, Leerzeichen | \d\d passt auf 42 |
[abc] | Eines von a, b, c | [aeiou] passt auf einen Vokal |
[^abc] | Beliebiges Zeichen außer a, b, c | [^0-9] passt auf eine Nicht-Ziffer |
* + ? | Null+, ein+, null-oder-eins | ab+ passt auf ab, abb |
{n} {n,m} | Genau n, zwischen n und m | \d{3} passt auf 555 |
^ $ | Anfang, Ende der Eingabe/Zeile | ^Hi passt auf ein führendes Hi |
(...) | Erfassungsgruppe | (\d{4}) erfasst vier Ziffern |
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class GroupsExample {
public static void main(String[] args) {
// Two capturing groups: year and month.
Pattern date = Pattern.compile("(\\d{4})-(\\d{2})");
Matcher m = date.matcher("Released 2025-11 to users");
if (m.find()) {
System.out.println("Full: " + m.group(0)); // 2025-11
System.out.println("Year: " + m.group(1)); // 2025
System.out.println("Month: " + m.group(2)); // 11
}
}
}Praxisbeispiel
Das folgende Programm kompiliert ein Muster für Telefonnummern und nutzt die gesamte API daran: Es durchläuft alle Treffer mit find(), liest Erfassungsgruppen und Match-Positionen, vergleicht find() mit matches() und schreibt den Text mit replaceAll() um. Führen Sie es aus, um die Engine in Aktion zu sehen.
Was aus der Ausführung zu entnehmen ist:
find()wird in einer Schleife aufgerufen und liefert zwei Treffer, sodass derselbeMatcherden Text einen Treffer nach dem anderen durchläuft, bis erfalsezurückgibt.group(1)undgroup(2)geben die in Klammern gesetzten Teilbereiche zurück (555und1234), währendgroup()ohne Argument den gesamten Match zurückgibt.start()undend()melden die Zeichenoffsets jedes Treffers, was verwendet wird, um den Originaltext hervorzuheben oder aufzuteilen.matches()auf den vollständigen Satz gibtfalsezurück, weil das Muster nicht den gesamten String abdeckt, während"555-1234"alleintrueergibt — Beweis dafür, dassmatches()nur auf die gesamte Eingabe angewendet wird.replaceAll("XXX-XXXX")schreibt alle Treffer in einem Durchgang um und erzeugt den maskierten Satz — ein Beispiel dafür, wie Muster Texttransformationen antreiben.
Nächste Schritte
Jetzt, da Sie die einzelnen Teile kennen — Pattern, Matcher und den Unterschied zwischen find() und matches() — vertiefen Sie Ihr Wissen mit den themenspezifischen Kapiteln:
- Pattern und Matcher — die vollständige API zum Kompilieren und Ausführen von Mustern.
- Regex-Syntax — jedes Metazeichen und jeder Escape-Code, erklärt.
- Zeichenklassen — Mengen, Bereiche und Negation.
- Quantifikatoren — gierige, zurückhaltende und possessive Wiederholung.
- Erfassungsgruppen — Extrahieren und Rückreferenzieren von Teilbereichen.
- Flags — Groß-/Kleinschreibung ignorieren, mehrzeilig und andere Modifikatoren.