Einfaches Suchen und Ersetzen

(Auszug aus "Reguläre Ausdrücke" von Jeffrey E. F. Friedl)

Die »Suchen und Ersetzen«-Funktionalität kann mit den bisher besprochenen Methoden programmiert werden, aber das Matcher-Objekt hält dafür bequemere Methoden bereit:

String replaceAll(String ersatztext)

Gibt ein String-Objekt zurück, in dem alle Textstücke, auf die die Regex gepasst hat, durch den ersatztext ersetzt wurden, wobei dieser Ersatztext nach den weiter unten beschriebenen Regeln (siehe den Abschnitt Der Ersatztext) beschriebenen Regeln behandelt wird.

Die Methode setzt die aktuelle Region auf den ganzen Suchstring zurück (indem sie intern reset aufruft) und kümmert sich folglich nicht um die Region. Unter Beispiele für Suchen und Ersetzen wird eine Abart von replaceAll beschrieben, die die Grenzen der Region respektiert.

Diese Methode ist auch über die replaceAll-Methode der String-Klasse zugänglich:

string.replaceAll(regex, ersatztext);

ist äquivalent zu:

Pattern.compile(regex).matcher(String).replaceAll(ersatztext)

String replaceFirst(String ersatztext)

Diese Methode arbeitet sehr ähnlich wie replaceAll, es wird aber nur der erste Treffer durch den ersatztext ersetzt.

Auch diese Methode hat ein Pendant mit der Methode replaceFirst für Strings, ganz analog zu replaceAll.

static String quoteReplacement(String text)

Seit Java 1.5 gibt es quoteReplacement, eine statische Methode, die einen String zurückgibt, der als ersatztext in den oben genannten Methoden verwendet werden soll. Sie maskiert dabei die Zeichen, die sonst bei der weiter unten beschriebenen Behandlung des Ersatztexts eine Rolle spielen könnten (dort finden Sie auch ein Programmbeispiel für quoteReplacement).

Beispiele für einfaches Suchen und Ersetzen

Im folgenden einfachen Beispiel wird jedes Vorkommen von »Java 1.5« durch »Java 5.0« ersetzt, es wird also Ingenieurjargon in Marketingsprache übersetzt:

String text = "Vor Java 1.5 war Java 1.4.2. Nach Java 1.5 kommt Java 1.6.";
String regex = "\\bJava\\s*1\\.5\\b";
Matcher m = Pattern.compile(regex).matcher(text);
String result = m.replaceAll("Java 5.0");
System.out.println(result);

Das ergibt:

Vor Java 5.0 war Java 1.4.2. Nach Java 5.0 kommt Java 1.6.

Wenn man die Pattern- und Matcher-Objekte später nicht mehr benötigt, kann man alles in einer Zeile aneinanderhängen:

Pattern.compile("\\bJava\\s*1\\.5\\b").matcher(text).replaceAll("Java 5.0")

(Wenn die Regex dagegen im selben Thread immer wieder benutzt wird, wäre es sinnvoll, das kompilierte Pattern-Objekt abzuspeichern, siehe dazu Die Factory-Methode Pattern.compile.)

Man kann im gleichen Schritt »Java 1.6« durch »Java 6.0« ersetzen, dafür ist nur eine kleine Änderung in der Regex notwendig (und die entsprechende Änderung im Ersatztext, die im nächsten Abschnitt besprochen wird).

Pattern.compile("\\bJava\\s*1\\.([56])\\b").matcher(text).replaceAll("Java $1.0")

Mit dem gleichen Text wie vorhin ergibt das:

Vor Java 5.0 war Java 1.4.2. Nach Java 5.0 kommt Java 6.0.

In allen diesen Beispielen könnte man replaceFirst statt replaceAll verwenden, es wird dann nur der erste Treffer ersetzt. In bestimmten Fällen kann dies das gewünschte Verhalten sein, aber es kann auch effizienter sein, dann nämlich, wenn bekannt ist, dass es ohnehin nur einen Treffer geben kann. (Sie haben dieses Wissen aufgrund von externen Informationen über die Daten oder weil die Regex so konstruiert ist.)

Der Ersatztext

Der Ersatztext im Argument von replaceAll und replaceFirst (außerdem auch bei der Methode appendReplacement aus dem nächsten Abschnitt) wird für jeden Treffer einzeln auf besondere Weise behandelt, bevor er den Treffer ersetzt:

  • Jedes ›$1‹, ›$2‹ usw. im Ersatztext wird durch den Text ersetzt, auf den das entsprechende Klammerpaar beim letzten Treffer gepasst hat. ($0 steht hierbei für den gesamten Treffer.)

    Wenn nach dem ›$‹-Zeichen ein anderes Zeichen als eine ASCII-Ziffer folgt, wird die Ausnahme IllegalArgumentException ausgelöst.

    Nach dem ›$‹-Zeichen sind nur Zahlen erlaubt, die für die entsprechenden regulären Ausdrücke sinnvoll sind. Wenn eine Regex beispielsweise drei Klammerpaare enthält, wird ›$25‹ im Ersatztext als $2 interpretiert, gefolgt von einer ›5‹. Ein ›$6‹ löst bei dieser Regex die Ausnahme IndexOutOfBoundsException aus.

  • Ein Backslash maskiert das folgende Zeichen; ein Dollarzeichen wird im Ersatztext also mit ›\$‹ angegeben. Analog muss man ›\\‹ für einen Backslash angeben. (Wenn der Ersatztext als String-Literal angegeben wird, müssen diese Backslashes verdoppelt werden, das ergibt also vier Backslashes hintereinander für einen Backslash im Ersatztext, "\\\\".) Wenn die Regex zwölf Klammerpaare enthält und nur der vom ersten Paar erkannte Text, gefolgt von einer ›2‹, eingesetzt werden soll, dann kann man dies mit ›$1\2‹ erreichen.

Wenn der Ersatztext ein String mit unbekanntem Inhalt ist, verwendet man am besten Matcher.quoteReplacement, das macht Metazeichen unschädlich, die möglicherweise darin enthalten sind. Wenn uRegex einen regulären Ausdruck und uRepl den Ersatztext unbekannten Inhalts enthält, dann wird so sichergestellt, dass der Treffer durch den exakten Ersatztext ausgewechselt wird:

Pattern.compile(uRegex).matcher(text).replaceAll(Matcher.quoteReplacement(uRepl))

  

<< 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