Java Regex-Flags
Reguläre Ausdrücke in Java mit Flags steuern — CASE_INSENSITIVE, MULTILINE, DOTALL, COMMENTS und inline (?i)-Syntax.
Ein Flag ändert die Interpretation eines regulären Ausdrucks, ohne das Muster selbst zu berühren. Derselbe Ausdruck kann Groß-/Kleinschreibung beachten oder nicht, eine Zeichenkette als eine oder als viele Zeilen behandeln und . über Zeilenumbrüche hinweggehen lassen oder davor anhalten — alles durch Flags gesteuert. In Java gibt es dafür zwei Wege: als int-Konstanten, die an Pattern.compile(pattern, flags) übergeben werden, oder als Inline-Schalter im Stil von (?i), die direkt im Muster stehen. Dieses Kapitel behandelt die Flags, die man täglich braucht, und wie man sie kombiniert.
Die zwei Arten, ein Flag zu setzen
Jedes Flag hat eine Konstante in der Pattern-Klasse. Sie wird als zweites Argument an compile übergeben:
Pattern p = Pattern.compile("error", Pattern.CASE_INSENSITIVE);Dasselbe Verhalten ist innerhalb des Musters als Inline-Modifikator verfügbar, sodass ein einfacher String-Regex seine eigenen Flags ohne zweites Argument tragen kann:
Pattern p = Pattern.compile("(?i)error"); // whole pattern, case-insensitive
Pattern q = Pattern.compile("(?i:error) CODE"); // only the group is case-insensitiveInline-Flags sind praktisch, wenn das Muster als einfache Zeichenkette weitergegeben wird — in einer Konfigurationsdatei, einer Datenbankspalte oder einer Annotation — wo kein int zusätzlich übergeben werden kann. Die Konstantenform ist klarer, wenn das Flag Teil des eigentlichen Codes ist.
Die Flags, die man tatsächlich verwendet
| Konstante | Inline | Wirkung |
|---|---|---|
CASE_INSENSITIVE | (?i) | ASCII-Buchstaben ohne Unterscheidung der Groß-/Kleinschreibung abgleichen |
MULTILINE | (?m) | ^ und $ treffen an jedem Zeilenrand, nicht nur am Anfang/Ende des Strings |
DOTALL | (?s) | . trifft auch Zeilentrenner (s = „single line") |
COMMENTS | (?x) | Nicht-escapte Leerzeichen ignorieren und # als Kommentar behandeln |
UNICODE_CASE | (?u) | CASE_INSENSITIVE auf Unicode-Buchstaben ausdehnen, nicht nur ASCII |
UNICODE_CHARACTER_CLASS | (?U) | \w, \d, \b nach Unicode-Regeln auswerten |
LITERAL | — | Das gesamte Muster als einfachen Text behandeln, keine Metazeichen |
Eine häufige Überraschung: CASE_INSENSITIVE allein faltet nur ASCII. Um akzentuierte oder nicht-lateinische Buchstaben ohne Groß-/Kleinschreibung abzugleichen, muss es mit UNICODE_CASE kombiniert werden.
Groß-/Kleinschreibung ignorieren
Standardmäßig unterscheidet ein regulärer Ausdruck Groß- und Kleinschreibung, sodass error nicht zu ERROR passt. Mit CASE_INSENSITIVE stimmen beide überein:
Pattern.compile("error").matcher("ERROR").find(); // false
Pattern.compile("error", Pattern.CASE_INSENSITIVE).matcher("ERROR").find(); // true
// For non-ASCII letters, add UNICODE_CASE:
Pattern.compile("é", Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE)
.matcher("É").find(); // trueZeilenverarbeitung: MULTILINE und DOTALL
Diese beiden sind unabhängig und werden oft verwechselt. MULTILINE ändert die Anker ^ und $; DOTALL ändert den Punkt ..
String text = "first line\nsecond line";
// Without MULTILINE, ^ matches only the very start of the input.
Pattern.compile("^second").matcher(text).find(); // false
// With MULTILINE, ^ matches the start of every line.
Pattern.compile("^second", Pattern.MULTILINE).matcher(text).find(); // true
// Without DOTALL, . will not cross the newline.
Pattern.compile("first.*second").matcher(text).find(); // false
// With DOTALL, . matches the newline too.
Pattern.compile("first.*second", Pattern.DOTALL).matcher(text).find(); // trueMULTILINE eignet sich beim zeilenweisen Durchsuchen mehrzeiliger Log- oder Dokumenttexte, während DOTALL benötigt wird, wenn ein einzelner Treffer mehrere Zeilen überspannen soll (ein HTML-Block, ein mehrzeiliger Datensatz).
Flags kombinieren
Flag-Konstanten sind Bit-Masken und werden daher mit dem bitweisen OR-Operator | kombiniert:
int flags = Pattern.MULTILINE | Pattern.CASE_INSENSITIVE | Pattern.DOTALL;
Pattern p = Pattern.compile("^error.*done$", flags);Das Inline-Äquivalent stapelt die Buchstaben: (?ims) setzt alle drei. Mit einem Minus lässt sich ein Flag auch innerhalb einer Gruppe deaktivieren: (?-i) schaltet die Groß-/Kleinschreibungsignorierung für den Rest des Musters ab.
Lesbare Muster mit COMMENTS
Das COMMENTS-Flag (Inline (?x)) lässt ein komplexes Muster aufatmen: Nicht-escapte Leerzeichen werden ignoriert, und # beginnt einen Kommentar bis zum Zeilenende. Damit wird ein unlesbarer Einzeiler zu etwas Wartbarem:
Pattern phone = Pattern.compile("""
\\d{3} # area code
- # separator
\\d{4} # line number
""", Pattern.COMMENTS);
phone.matcher("555-1234").matches(); // trueDa echte Leerzeichen ignoriert werden, kann ein wörtliches Leerzeichen mit \\s, \\ oder einer Zeichenklasse wie [ ] abgeglichen werden.
Ein durchgearbeitetes Beispiel: ein Ausdruck, viele Flags
Dieses Programm führt dieselbe Handvoll Muster mit und ohne Flags aus, damit jeder Flag-Wechsel des Ergebnisses sichtbar wird. Es zählt Treffer ohne Groß-/Kleinschreibung, verankert Zeilen mit MULTILINE, überspannt Zeilenumbrüche mit DOTALL, kombiniert Flags mit | und verwendet sowohl globale als auch auf Gruppen beschränkte Inline-Schalter.
Was man aus der Ausgabe mitnehmen kann:
CASE_INSENSITIVEfand 2 Vorkommen vonerror(das großgeschriebeneERRORund das kleingeschriebeneerror), während das Standard-Muster nur 1 fand — Beweis dafür, dass die Groß-/Kleinschreibungsunterscheidung aktiv ist, bis man das Flag explizit anfordert.MULTILINEließ^error:.*$die mittlere Zeile des Logs treffen und gaberror: timeoutaus; ohne das Flag würden^und$nur die Enden des gesamten Strings verankern, sodass diese innere Zeile nie passen würde.DOTALLließwarn.*infoüber die zwei eingebetteten Zeilenumbrüche hinwegspringen und liefertetrue, während dasselbe Muster ohne das Flagfalsezurückgab, weil.standardmäßig vor einem Zeilentrenner stoppt.- Das kombinierte
MULTILINE | CASE_INSENSITIVE-Muster traf^ERRORauf eine Zeile, die tatsächlich mit dem Kleinbuchstabenerror:beginnt —truebestätigt, dass beide Flags gleichzeitig durch eine einzige bitweise-OR-Maske angewendet wurden. - Das begrenzte
(?i:hello) WORLDtrafHELLO WORLD(true), aber nichtHELLO world(false): Die(?i:...)-Gruppe faltete die Schreibweise nur fürhellound ließ das nachfolgendeWORLDstreng groß-/kleinschreibungssensitiv — genau die Präzision, die Inline-Scoping bietet.
Verwandte Themen
- Java Regular Expressions — Introduction — wie
PatternundMatcherzusammenpassen. - Pattern and Matcher — die Klassen, die die obigen Flags verwenden.
- Regex Syntax und Character Classes — die Metazeichen, die Flags verändern.
- Quantifiers und Groups — wo begrenzte Inline-Flags wie
(?i:...)am nützlichsten sind.