Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 7. Auflage |
<< | < | > | >> | API | Kapitel 18 - 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, 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. |
|
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.
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 |
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 |
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 |
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 |
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 |