Suchen und Ersetzen im Detail
(Auszug aus "Reguläre Ausdrücke" von Jeffrey E. F. Friedl)
Es gibt zwei weitere Methoden, die den Zugang zur »Suchen und Ersetzen«-Mechanik des Matcher-Objekts ermöglichen. Diese Methoden bauen den Resultatstring in einem anzugebenden StringBuffer auf. Die erste Methode wird nach jedem Treffer aufgerufen und fügt den Ersatztext in den Resultatstring ein, außerdem auch den Text zwischen den Treffern. Die zweite Methode wird aufgerufen, nachdem alle Treffer gefunden sind; mit ihr kann man den Text nach dem letzten Treffer anfügen.
Matcher appendReplacement(StringBuffer resultat, String ersatztext)
Diese Methode wird unmittelbar nach einem Treffer (mit find) aufgerufen. Sie hängt zwei weitere Strings an den gegebenen StringBuffer an: den Text aus dem Suchtext vor dem Treffer und den ersatztext, der die oben beschriebene Sonderbehandlung erfahren hat.
Nehmen wir an, unser Matcher-Objekt m verknüpft die Regex ˹\w+˼ mit dem Suchstring ›-->ein+Test<--‹. Beim ersten Durchgang der while
while (m.find())
m.appendReplacement(sb, "XXX")
wird mit der Methode find der unterstrichene Teil in ›-->ein+Test<--‹ gefunden.
Mit dem Aufruf von appendReplacement wird an den StringBuffer sb zuerst der Text vor dem Treffer, ›-->‹, angehängt. Der eigentliche Treffer wird übersprungen, stattdessen wird der Ersatztext ›XXX‹ an sb angehängt.
Beim zweiten Schleifendurchgang wird mit find ›-->ein+Test<--‹ gefunden. Mit der Methode appendReplacement wird zuerst der Text vor dem Treffer, also ›+‹, angehängt, danach wieder der Ersatztext ›XXX‹.
Der String sb hat nun den Wert ›-->XXX+XXX‹, und das Objekt m befindet sich im Suchstring an der Position ›-->ein+Test▵<--‹.
Jetzt verstehen wir auch, wofür die appendTail-Methode gut ist.
StringBuffer appendTail(StringBuffer resultat)
Wird nach dem letzten Treffer aufgerufen (oder zumindest, wenn keine weiteren Treffer mehr erwünscht sind – man darf durchaus früher aufhören). Die Methode fügt den Text nach dem letzten Treffer aus dem Suchstring an den Resultatstring in StringBuffer an.
Beim letzten Beispiel
m.appendTail(sb)
wird also ›<--‹ an sb angehängt. Damit erhalten wir ›-->XXX+XXX<--‹, und das »Suchen und Ersetzen« ist abgeschlossen.
Beispiele für Suchen und Ersetzen
Im folgenden Beispiel wird gezeigt, wie man mit diesen Primitiven seine eigene Version von replaceAll aufbauen kann (das Beispiel dient nur zur Illustration):
public static String replaceAll(Matcher m, String ersatztext) {
m.reset(); // Matcher-Objekt initialisieren.
StringBuffer resultat = new StringBuffer(); // Darin wird die neue Version aufgebaut.
while (m.find())
m.appendReplacement(resultat, ersatztext);
m.appendTail(resultat);
return resultat.toString(); // In einen String verwandeln und zurückgeben.
}
Wie die echte replaceAll-Methode beachtet auch diese die aktuelle Region nicht (siehe Die Region des Matchers), sondern setzt sie zu Beginn auf den gesamten Suchstring.
Das ist in manchen Fällen nicht das gewünschte Verhalten. Das folgende Programmstück ist eine Version von replaceAll, die die aktuelle Region respektiert. Die veränderten Teile sind in den hervorgehobenen Zeilen:
public static String replaceAllRegion(Matcher m, String ersatztext) {
Integer start = m.regionStart();
Integer end = m.regionEnd();
m.reset().region(start, end); // Matcher initialisieren, aber Region erhalten.
StringBuffer resultat = new StringBuffer(); // Darin wird die neue Version aufgebaut.
while (m.find())
m.appendReplacement(resultat, ersatztext);
m.appendTail(resultat);
return resultat.toString(); // In einen String verwandeln und zurückgeben.
}
Die Kombination der Methoden reset und region in einer einzigen Anweisung ist ein Beispiel für das Verketten von Methoden, das bei Verketten von Methoden näher erläutert wird.
Das folgende Programmstück ist nur ein wenig komplizierter, es verwandelt die Celsius-Temperaturwerte in der Variablen temps in Fahrenheit:
// Matcher aufbauen, der in der Variablen "temps" nach Zahlen, gefolgt von einem "C", sucht.
Matcher m = Pattern.compile("(\\d+(?:\\.(\\d+))?)C\\b").matcher(temps);
StringBuffer resultat = new StringBuffer(); // Darin bauen wir die veränderte Kopie auf.
while (m.find()) {
float celsius = Float.parseFloat(m.group(1)); // Gefundene Ziffern -> Fließkommazahl.
int fahrenheit = (int) (celsius * 9/5 + 32); // In Fahrenheit umrechnen.
m.appendReplacement(resultat, fahrenheit + "F"); // In das Resultat einfügen.
}
m.appendTail(resultat);
System.out.println(resultat.toString()); // Resultat ausgeben.
Wenn temps z.B. ›von 36.3C bis 40.1C.‹ enthält, wird ›von 97F bis 104F.‹ ausgegeben.
<< zurück | vor >> |
Tipp der data2type-Redaktion: Zum Thema Reguläre Ausdrücke bieten wir auch folgende Schulungen zur Vertiefung und professionellen Fortbildung an: |
Copyright der deutschen Ausgabe © 2008 by O’Reilly Verlag GmbH & Co. KG
Für Ihren privaten Gebrauch dürfen Sie die Online-Version ausdrucken.
Ansonsten unterliegt dieses Kapitel aus dem Buch "Reguläre Ausdrücke" denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.
O’Reilly Verlag GmbH & Co. KG, Balthasarstr. 81, 50670 Köln