Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 5. Auflage |
<< | < | > | >> | API | Kapitel 17 - Utility-Klassen II |
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.
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 und so weiter. Wobei der Stern - wie allgemein üblich - für eine beliebige Menge von Zeichen steht. Der obige Ausdruck ließt sich also: »Eine beliebige Anzahl von kleinen as, gefolgt von 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 17.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 Baskslash-Zeichen (\) in Strings reserviert ist und durch einen doppelten Backslash (\\) kodiert werden muss. |
|
Während die Klasse Pattern einen regulären Ausdruck repräsentiert, können Sie mit Hilfe der Methode matcher ein Matcher-Objekt erzeugen, das verwendet werden kann, um eine beliebige Zeichenkette auf den regulären Ausdruck zu testen.
Die Klassen für Pattern und Matcher sind dabei getrennt worden, da erstere auf der einen Seite relativ komplexe Objekte sind, auf der anderen allerdings auch threadsafe programmiert sind und in nebenläufigen Programmen von verschiedenen Threads gemeinsam genutzt werden können. Matcher auf der anderen Seite sind leichtgewichtige Objekte, die nur von einem Thread verwendet werden sollten. In einem Satz: Sie können jeden benötigten Ausdruck durch ein global zu verwendendes Pattern beschreiben und von diesem bei Bedarf beliebig viele Matcher-Objekte erzeugen lassen.
Neben der Möglichkeit, Zeichenketten untereinander auf (partielle) Gleichheit zu überprüfen, wie es in Abschnitt 11.2.4 beschrieben wird, 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 /* Listing1701.java */ 002 003 import java.util.regex.*; 004 005 public class Listing1701 006 { 007 public static void main(String[] args) 008 { 009 // Erzeugen eines Pattern-Objektes für den Ausdruck a*b 010 Pattern p = Pattern.compile("a*b"); 011 012 // Erzeugen eines Matcher-Objektes 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 } |
Listing1701.java |
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ück gibt 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 und helfen so, wertvolle Ressourcen zu sparen. Um nur eine einzige Zeichenkette auf ein Pattern zu testen, kann man aber auch die folgende Kurzform verwenden:
001 /* Listing1702.java */ 002 003 import java.util.regex.*; 004 005 public class Listing1702 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 } |
Listing1702.java |
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. Seit dem JDK 5 stellt die Klasse String nämlich die Methode matches zur Verfügung, hinter der sich nichts anderes als oben beschriebene Kurzform verbirgt.
001 /* Listing1703.java */ 002 003 public class Listing1703 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 } |
Listing1703.java |
Neben dem Test auf Äquivalenz erlauben es reguläre Ausdrücke auch, Teile einer Zeichenkette zu ersetzen oder lange Zeichenketten in mehrere Teile aufzuspalten (engl. Splitting). Für letzteres besitzt die Klasse Pattern die Methoden split
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 wieviele 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 /* Listing1704.java */ 002 003 import java.util.regex.*; 004 005 public class Listing1704 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 } |
Listing1704.java |
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 11.2.7 beschrieben.
Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 5. Auflage, Addison Wesley, Version 5.0.2 |
<< | < | > | >> | API | © 1998, 2007 Guido Krüger & Thomas Stark, http://www.javabuch.de |