Reguläre Ausdrücke, auch als Regex oder RegExp bekannt, sind leistungsstarke Werkzeuge für das Musterabgleichen und die Textmanipulation. In Java werden reguläre Ausdrücke durch das Paket java.util.regex
implementiert, das eine umfangreiche Sammlung von Klassen und Methoden für die Arbeit mit Mustern bereitstellt. Dieser Artikel soll einen umfassenden Leitfaden für reguläre Ausdrücke in Java bieten, der die Grundlagen, fortgeschrittenen Einsatz und bewährte Praktiken abdeckt.
Verständnis von Regulären Ausdrücken
Im Kern ist ein regulärer Ausdruck eine Zeichenfolge, die ein Suchmuster definiert. Diese Muster können verwendet werden, um Zeichenfolgen abzugleichen, Eingaben zu validieren oder komplexe Textmanipulationen durchzuführen. In Java wird die Pattern
-Klasse verwendet, um einen kompilierten regulären Ausdruck zu repräsentieren, und die Matcher
-Klasse hilft dabei, das Muster auf eine gegebene Eingabe anzuwenden.
Grundlegende Muster und Zeichen
Beginnen wir mit den grundlegenden Bausteinen regulärer Ausdrücke.
- Literale: Zeichen, die sich selbst entsprechen. Zum Beispiel wird der reguläre Ausdruck
abc
die Zeichenfolge „abc“ genau abgleichen. - Zeichenklassen: Definieren eine Menge von Zeichen, die abgeglichen werden sollen. Beispielsweise wird
[aeiou]
zu jedem Vokal passen, und[^0-9]
zu jedem Nicht-Ziffern-Zeichen. - Quantifizierer: Definieren die Anzahl der Vorkommen eines Zeichens oder einer Gruppe. Häufig verwendete Quantifizierer sind
*
(null oder mehr),+
(eins oder mehr),?
(null oder eins) und{n, m}
(zwischen n und m Vorkommen). - Metazeichen: Besondere Zeichen mit vordefinierten Bedeutungen. Beispiele sind
.
(beliebiges Zeichen),^
(Anfang einer Zeile),$
(Ende einer Zeile) und\
(Escape-Zeichen).
Die Klasse Pattern
In Java werden reguläre Ausdrücke in Pattern
-Objekte kompiliert. Die Klasse Pattern
bietet verschiedene statische Methoden zum Erstellen von Mustern, wie compile()
und matches()
.
import java.util.regex.Pattern;
public class RegexBeispiel {
public static void main(String[] args) {
// Erstellen eines Musters
Pattern pattern = Pattern.compile("[0-9]+");
// Abgleichen einer Zeichenfolge
boolean istTreffer = pattern.matcher("12345").matches();
System.out.println(istTreffer); // Ausgabe: true
}
}
Code-Sprache: JavaScript (javascript)
Die Klasse Matcher
Nachdem ein Muster kompiliert wurde, wird die Klasse Matcher
verwendet, um das Muster auf eine bestimmte Eingabezeichenfolge anzuwenden. Sie bietet Methoden wie matches()
, find()
und group()
.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MatcherBeispiel {
public static void main(String[] args) {
// Erstellen eines Musters
Pattern pattern = Pattern.compile("\\b\\d+\\b");
// Erstellen eines Matchers
Matcher matcher = pattern.matcher("123 456 789");
// Suchen von Treffern
while (matcher.find()) {
System.out.println("Treffer: " + matcher.group());
}
}
}
Code-Sprache: JavaScript (javascript)
In diesem Beispiel passt das Muster \b\d+\b
auf eine oder mehrere Ziffern zwischen Wortgrenzen.
Fortgeschrittene Verwendung
Reguläre Ausdrücke werden mächtiger, wenn grundlegende Elemente zu komplexen Mustern kombiniert werden.
Gruppen und Erfassen
Gruppen sind Teile eines regulären Ausdrucks, die in Klammern eingeschlossen sind. Sie ermöglichen es, Quantifizierer auf mehrere Zeichen anzuwenden.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class GruppenBeispiel {
public static void main(String[] args) {
// Erstellen eines Musters mit Gruppen
Pattern pattern = Pattern.compile("([a-z]+)(\\d+)");
// Erstellen eines Matchers
Matcher matcher = pattern.matcher("abc123");
// Extrahieren von erfassten Gruppen
if (matcher.matches()) {
String buchstaben = matcher.group(1);
String ziffern = matcher.group(2);
System.out.println("Buchstaben: " + buchstaben + ", Ziffern: " + ziffern);
}
}
}
Code-Sprache: JavaScript (javascript)
In diesem Beispiel erfasst das Muster ([a-z]+)(\\d+)
eine oder mehrere Buchstaben gefolgt von einer oder mehreren Ziffern.
Positive und Negative Lookahead/Lookbehind
Lookahead- und Lookbehind-Assertionen ermöglichen es, Bedingungen zu definieren, die für einen Treffer erfüllt sein müssen, ohne den abgeglichenen Text im Ergebnis zu erfassen.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class LookaroundBeispiel {
public static void main(String[] args) {
// Positive Lookahead-Assertion
Pattern pattern = Pattern.compile("\\d(?=\\D)");
// Erstellen eines Matchers
Matcher matcher = pattern.matcher("1a 2b 3c");
// Suchen von Treffern
while (matcher.find()) {
System.out.println("Treffer: " + matcher.group());
}
}
}
Code-Sprache: JavaScript (javascript)
In diesem Beispiel passt das Muster \d(?=\D)
auf eine Ziffer nur, wenn sie von einem Nicht-Ziffer-Zeichen gefolgt wird.
Gierige vs. Faule Quantifizierer
Quantifizierer in regulären Ausdrücken sind standardmäßig gierig, d. h., sie passen so viel wie möglich an. Wenn ein ?
nach einem Quantifizierer steht, wird dieser faul und passt so wenig wie möglich an.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class GierigFauleBeispiel {
public static void main(String[] args) {
// Gieriger Quantifizierer
Pattern gierigesMuster = Pattern.compile("<.*>");
// Fauler Quantifizierer
Pattern faulesMuster = Pattern.compile("<.*?>");
// Erstellen von Matchern
Matcher gierigerMatcher = gierigesMuster.matcher("<tag>inhalt</tag>");
Matcher faulerMatcher = faulesMuster.matcher("<tag>inhalt</tag>");
// Suchen von Treffern
while (gierigerMatcher.find()) {
System.out.println("Gieriger Treffer: " + gierigerMatcher.group());
}
while (faulerMatcher.find()) {
System.out.println("Faule Treffer: " + faulerMatcher.group());
}
}
}
Code-Sprache: JavaScript (javascript)
In diesem Beispiel passt das gierige Muster <.*>
auf die gesamte Zeichenkette zwischen dem ersten <
und dem letzten >
, während das faule Muster <.*?>
nur das zwischen jedem Paar von Tags passt.
Bewährte Praktiken und Tipps
- Bevorzugen Sie kompilierte Muster:
Kompilieren Sie reguläre Ausdrücke immer, bevor Sie sie wiederholt verwenden. Die Kompilierung ist eine aufwändige Operation, und die Verwendung von kompilierten Mustern verbessert die Leistung.
// Bevorzugen Sie dies
Pattern muster1 = Pattern.compile("\\d+");
Pattern muster2 = Pattern.compile("\\w+");
Code-Sprache: JavaScript (javascript)
- Verwenden Sie Zeichenklassen mit Bedacht:
Zeichenklassen wie[a-z]
sind standardmäßig auf Groß-/Kleinschreibung empfindlich. Wenn ein Fall-unsensitives Abgleichen gewünscht ist, verwenden Sie die(?i)
-Flagge.
// Groß-/Kleinschreibung beachten
Pattern muster = Pattern.compile("[a-z]");
// Groß-/Kleinschreibung ignorieren
Pattern muster = Pattern.compile("(?i)[a-z]");
Code-Sprache: JavaScript (javascript)
- Escape von Metazeichen:
Achten Sie auf Metazeichen und escapen Sie sie, wenn sie als Literale behandelt werden sollen.
// Abgleichen eines literalen Punktes
Pattern muster = Pattern.compile("\\.");
Code-Sprache: JavaScript (javascript)
- Validieren Sie Eingaben mit
matches()
:
Die Methodematches()
überprüft, ob die gesamte Eingabezeichenfolge dem Muster entspricht. Verwenden Sie sie zur Eingabevalidierung.
// Überprüfen, ob eine Zeichenfolge eine Zahl ist
if ("123".matches("\\d+")) {
System.out.println("Gültige Zahl");
}
Code-Sprache: JavaScript (javascript)