Titel   Inhalt   Suchen   Index   DOC  Handbuch der Java-Programmierung, 7. Auflage
 <<    <     >    >>   API  Kapitel 18 - Utility-Klassen II

18.1 Reguläre Ausdrücke



Seit der Version 1.4 enthält das JDK auch Klassen zur Verwendung von regulären Ausdrücken. Dabei handelt es sich um Muster, die Mengen von Zeichenketten beschreiben und stellvertretend für diese stehen.

Wenn Sie schon einmal die Datei-Suchfunktionalität Ihres Betriebssystems verwendet haben, haben Sie wahrscheinlich - ohne es zu bemerken - einen regulären Ausdruck verwendet. Um beispielsweise alle Dateien in einem Ordner aufzulisten, suchen Sie typischerweise mit dem Muster *.*. Dabei steht der Stern stellvertretend für eine beliebige Zeichenkette und schon haben Sie einen (wenn auch recht einfachen) regulären Ausdruck verwendet, um nicht jeden Dateinamen einzeln hinschreiben zu müssen.

18.1.1 Die Klasse Pattern

Um einen regulären Ausdruck zu erzeugen, hält das JDK die Klasse Pattern im Package java.util.regex bereit. So ist a*b beispielsweise ein Pattern zur Beschreibung der Zeichenketten b, ab, aab, aaab und so weiter. Dabei steht der Stern für eine beliebige Anzahl des links neben ihm stehenden Zeichens. Der obige Ausdruck liest sich also wie »Eine beliebige Anzahl von kleinen as (inkl. null), gefolgt von genau einem b«.

Die folgende Tabelle zeigt einige häufig verwendete Platzhalter. Die Möglichkeiten regulärer Ausdrücke in Java sind dabei so vielfältig, dass sie allein ein ganzes Kapitel füllen würden. Eine vollständige Liste findet man z.B. in den JavaDocs zur Klasse Pattern.

Symbol Bedeutung
. Ein beliebiges einzelnes Zeichen
* Eine beliebige Menge von Zeichen
\d Eine Zahl zwischen 0 und 9
\D Ein Zeichen, das keine Zahl darstellt
\s Ein beliebiges Leerzeichen (Whitespace)
\S Ein Zeichen, das kein Leerzeichen ist

Tabelle 18.1: Häufige Elemente für reguläre Ausdrücke in Java

Achten Sie bei der Programmierung von regulären Ausdrücken darauf, dass das Backslash-Zeichen (\) in Strings reserviert ist und durch einen doppelten Backslash (\\) kodiert werden muss.

 Warnung 

18.1.2 Die Klasse Matcher

Während die Klasse Pattern den regulären Ausdruck an sich repräsentiert, erzeugt man mit Hilfe der Methode matcher ein Matcher-Objekt, das dazu verwendet werden kann, eine beliebige Zeichenkette auf den regulären Ausdruck zu testen.

Die Klassen für Pattern und Matcher wurden dabei bewusst getrennt. Bei den Pattern handelt es sich um relativ komplexe Objekte, die threadsafe programmiert sind und in nebenläufigen Programmen von verschiedenen Threads gemeinsam genutzt werden können. Die Matcher auf der anderen Seite sind leichtgewichtige Objekte, die nur von einem Thread zur Zeit verwendet werden sollten. Mit anderen Worten: Man kann jeden benötigten Ausdruck durch ein wieder verwendbares Pattern beschreiben und für dieses je nach Bedarf beliebig viele Matcher-Objekte erzeugen lassen.

18.1.3 Vergleich einer Zeichenkette mit einem regulären Ausdruck

Neben der Möglichkeit, Zeichenketten untereinander auf (partielle) Gleichheit zu überprüfen, wie es in Abschnitt 12.2.4 beschrieben wurde, kann mit Hilfe von regulären Ausdrücken auch überprüft werden, ob eine Zeichenkette von einem Ausdruck beschrieben wird. Hierzu erzeugt man zunächst ein Pattern-Objekt, das den Ausdruck repräsentiert, und anschließend ein Matcher-Objekt, das zum Testen verwendet werden kann. Das folgende Listing verdeutlicht dies:

001 /* Listing1801.java */
002 
003 import java.util.regex.*;
004 
005 public class Listing1801
006 {
007   public static void main(String[] args)
008   {
009     // Erzeugen eines Pattern-Objekts für den Ausdruck a*b
010     Pattern p = Pattern.compile("a*b");
011 
012     // Erzeugen eines Matcher-Objekts für die Zeichenkette
013     Matcher m = p.matcher("aaaaab");
014 		
015     // Test, ob die Zeichenkette vom Ausdruck beschrieben wird
016     boolean b = m.matches();  
017   }
018 }
Listing1801.java
Listing 18.1: Reguläre Ausdrücke

Auffällig an diesem Listing ist, dass weder Pattern noch Matcher über einen Konstruktor erzeugt werden. Stattdessen verwenden wir die statische Methode compile, die ein Pattern- Objekt zurückgibt, und die Methode matcher, um einen Matcher zu erzeugen. Der Grund liegt möglicherweise darin, dass das JDK die Pattern auf diese Weise intern cachen kann und auch bei der »zweiten« Kompilierung das gleiche Objekt zurückgibt - aber verlassen Sie sich nicht darauf.

Wie bereits weiter oben beschrieben, lassen sich einmal erzeugte Pattern für viele Matcher wiederverwenden, um Ressourcen zu sparen. Will man nur eine einzige Zeichenkette auf ein Pattern testen, kann man aber auch folgende Kurzform verwenden:

001 /* Listing1802.java */
002 
003 import java.util.regex.*;
004 
005 public class Listing1802
006 {
007   public static void main(String[] args)
008   {
009     // Testet die Zeichenkette auf das Pattern
010     boolean b = Pattern.matches("a*b", "aaaaab");
011   }
012 }
Listing1802.java
Listing 18.2: Kurzer Zeichenkettenvergleich mit regulären Ausdrücken

Bei dieser Kurzversion wird das Pattern intern kompiliert, anschließend ein passender Matcher erzeugt und schließlich nur das Resultat zurückgegeben. Dieser »Einzeiler« ist zwar markant, allerdings lässt sich das Pattern nicht wiederverwenden.

Und es geht sogar noch kürzer und ohne explizite Verwendung der Klassen im Package java.util.regex, wie es das folgende Listing demonstriert. Dazu stellt nämlich die Klasse String die Methode matches zur Verfügung, hinter der sich nichts anderes als oben beschriebene Kurzform verbirgt.

001 /* Listing1803.java */
002 
003 public class Listing1803
004 {
005   public static void main(String[] args)
006   {
007     // Testet die Zeichenkette auf das Pattern
008     boolean b = "aaaaab".matches("a*b");
009   }
010 }
Listing1803.java
Listing 18.3: Strings und reguläre Ausdrücke

18.1.4 Teilen einer Zeichenkette mit einem regulären Ausdruck

Neben dem Test auf Äquivalenz erlauben es reguläre Ausdrücke auch, Teile einer Zeichenkette zu ersetzen oder lange Zeichenketten in mehrere Teile aufzuspalten. Letzteres erfolgt mit der Methode split der Klasse Pattern:

public String[] split(CharSequence input)

public String[] split(CharSequence input, int limit)
java.util.regex.Pattern

Mit Hilfe des zweiten Parameters kann dabei angegeben werden, in wie viele Teile die Zeichenkette maximal aufgeteilt werden soll. Er ist eine Obergrenze für die Größe des zurückgegebenen Arrays. Wird als Limit eine negative Zahl angeben, wird die Zeichenkette beliebig oft durch das Pattern geteilt. Beide Methoden verhalten sich dann identisch.

Das folgende Listing zeigt das Splitting der Zeichenkette, die uns schon im Kapitel über Strings begegnet ist:

001 /* Listing1804.java */
002 
003 import java.util.regex.*;
004 
005 public class Listing1804
006 {
007   public static void main(String[] args)
008   {
009     // Der zu verwendende Testsatz
010     String satz = "Dies ist nur ein Test";
011     
012     // Jedes Whitespace-Zeichen soll zur 
013     // Trennung verwendet werden
014     Pattern p = Pattern.compile("\\s");
015     
016     // Verwendung der Methode split
017     String[] result = p.split(satz);
018     for (int x=0; x<result.length; x++) {
019       System.out.println(result[x]);
020     }
021   }
022 }
Listing1804.java
Listing 18.4: Zerlegen von Zeichenketten

Soll das Pattern nicht wiederverwendet werden, kann man auch in diesem Fall auf eine äquivalente Methode der Klasse String zurückgreifen, wie bereits in Abschnitt 12.2.7 beschrieben.


 Titel   Inhalt   Suchen   Index   DOC  Handbuch der Java-Programmierung, 7. Auflage, Addison Wesley, Version 7.0
 <<    <     >    >>   API  © 1998, 2011 Guido Krüger & Heiko Hansen, http://www.javabuch.de