Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort
1 Java ist auch eine Sprache
2 Sprachbeschreibung
3 Klassen und Objekte
4 Der Umgang mit Zeichenketten
5 Mathematisches
6 Eigene Klassen schreiben
7 Angewandte Objektorientierung
8 Exceptions
9 Generics, innere Klassen
10 Die Klassenbibliothek
11 Threads und nebenläufige Programmierung
12 Datenstrukturen und Algorithmen
13 Raum und Zeit
14 Dateien und Datenströme
15 Die eXtensible Markup Language (XML)
16 Grafische Oberflächen mit Swing
17 Grafikprogrammierung
18 Netzwerkprogrammierung
19 Verteilte Programmierung mit RMI und Web–Services
20 JavaServer Pages und Servlets
21 Applets
22 Midlets und die Java ME
23 Datenbankmanagement mit JDBC
24 Reflection und Annotationen
25 Logging und Monitoring
26 Sicherheitskonzepte
27 Java Native Interface (JNI)
28 Dienstprogramme für die Java-Umgebung
Stichwort

Download:
- ZIP, ca. 14,1 MB
Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Java ist auch eine Insel (8. Auflage) von Christian Ullenboom
Programmieren mit der Java Standard Edition Version 6
Buch: Java ist auch eine Insel (8. Auflage)

Java ist auch eine Insel (8. Aufl.)
8., aktual. Auflage, geb., mit DVD
1.475 S., 49,90 Euro
Galileo Computing
ISBN 978-3-8362-1371-4
Pfeil 4 Der Umgang mit Zeichenketten
Pfeil 4.1 Einzelne Zeichen mit der Character-Klasse behandeln
Pfeil 4.2 Strings und deren Anwendung
Pfeil 4.2.1 String-Literale als String-Objekte für konstante Zeichenketten
Pfeil 4.2.2 String-Länge und Test auf Leerstring
Pfeil 4.2.3 Nach enthaltenen Zeichen und Zeichenfolgen suchen
Pfeil 4.2.4 Gut, dass wir verglichen haben
Pfeil 4.2.5 String-Teile extrahieren
Pfeil 4.2.6 Strings anhängen, Groß-/Kleinschreibung und Leerraum
Pfeil 4.2.7 Suchen und ersetzen
Pfeil 4.2.8 String-Objekte mit Konstruktoren neu anlegen
Pfeil 4.3 Konvertieren zwischen Primitiven und Strings
Pfeil 4.3.1 Unterschiedliche Typen in String-Repräsentationen konvertieren
Pfeil 4.3.2 String in primitives Element konvertieren
Pfeil 4.4 Veränderbare Zeichenketten mit StringBuilder/StringBuffer
Pfeil 4.4.1 Anlegen von StringBuilder-/StringBuffer-Objekten
Pfeil 4.4.2 Die Länge eines StringBuilder-/StringBuffer-Objekts
Pfeil 4.4.3 Daten anhängen
Pfeil 4.4.4 Zeichen(folgen) setzen, erfragen, löschen und umdrehen
Pfeil 4.4.5 Vergleichen von String/StringBuilder/StringBuffer
Pfeil 4.4.6 hashCode() bei StringBuffer/StringBuilder
Pfeil 4.5 Sprachabhängiges Vergleichen und Normalisierung
Pfeil 4.5.1 Die Klasse Collator
Pfeil 4.5.2 Effiziente interne Speicherung für die Sortierung
Pfeil 4.5.3 Normalisierung
Pfeil 4.6 Reguläre Ausdrücke
Pfeil 4.6.1 Arbeiten mit der Fassade: String.matches()
Pfeil 4.6.2 Die Klassen Pattern und Matcher
Pfeil 4.6.3 Quantifizierer und Wiederholungen
Pfeil 4.6.4 Finden und nicht matchen
Pfeil 4.6.5 Gierige und nicht gierige Operatoren
Pfeil 4.6.6 Mit MatchResult alle Ergebnisse einsammeln
Pfeil 4.7 Zerlegen von Zeichenketten
Pfeil 4.7.1 Splitten von Zeichenketten mit split()
Pfeil 4.7.2 Die Klasse Scanner
Pfeil 4.7.3 StringTokenizer
Pfeil 4.7.4 BreakIterator als Zeichen-, Wort-, Zeilen- und Satztrenner
Pfeil 4.8 Zeichenkodierungen und Base64
Pfeil 4.8.1 Über die Klasse String Kodierungen vornehmen
Pfeil 4.8.2 Konvertieren mit OutputStreamWriter-Klassen
Pfeil 4.8.3 Das Paket java.nio.charset
Pfeil 4.8.4 Base64-Kodierung
Pfeil 4.9 Formatieren von Ausgaben
Pfeil 4.9.1 Formatieren mit format() aus String
Pfeil 4.9.2 Die Format-Klassen im Überblick
Pfeil 4.9.3 Zahlen, Prozente und Währungen mit NumberFormat und DecimalFormat formatieren
Pfeil 4.10 Zum Weiterlesen


Galileo Computing - Zum Seitenanfang

4.6 Reguläre Ausdrücke Zur nächsten ÜberschriftZur vorigen Überschrift

Ein regulärer Ausdruck (engl. regular expression) ist eine Beschreibung eines Musters (engl. pattern). Reguläre Ausdrücke werden bei der Zeichenkettenverarbeitung beim Suchen und Ersetzen eingesetzt. Für folgende Szenarien bietet die Java-Bibliothek entsprechende Methoden an:

  • Frage nach dem kompletten Übereinstimmen: Passt eine Zeichenfolge komplett auf ein Muster? Wir nennen das match.
  • Finde Teilstrings: Das Pattern beschreibt nur einen Teilstring, und gesucht sind alle Vorkommen dieses Musters in einem Suchstring.
  • Ersetze Teilfolgen: Das Pattern beschreibt Wörter, die durch andere Wörter ersetzt werden.
  • Zerlegen einer Zeichenfolge: Das Muster steht für Trennzeichnen, sodass nach dem Zerlegen eine Sammlung von Zeichenfolgen entsteht.

Ein Pattern-Matcher ist die »Maschine«, die reguläre Ausdrücke verarbeitet. Zugriff zu dieser Mustermaschine bietet die Klasse Matcher. Dazu kommt die Klasse Pattern, die die regulären Ausdrücke in einem vorcompilierten Format repräsentiert. Beide Klassen befinden sich im Paket java.util.regex. Um die Sache etwas zu vereinfachen, gibt es bei String zwei kleine Hilfsmethoden, die im Hintergrund auf die Klassen verweisen, um eine einfachere API anbieten zu können; das nennt sich auch Fassaden-Methoden.


Galileo Computing - Zum Seitenanfang

4.6.1 Arbeiten mit der Fassade: String.matches() Zur nächsten ÜberschriftZur vorigen Überschrift

Die statische Funktion Pattern.matches() und die Objektmethode matches() der Klasse String testen, ob ein regulärer Ausdruck eine Zeichenfolge komplett beschreibt.


Beispiel Teste, ob eine Zeichenfolge in einfachen Hochkommata eingeschlossen ist:

Listing 4.10 RegularExpression.java, main()

System.out.println( Pattern.matches( "'.*'", "'Hallo Welt'" ) ); // true 
System.out.println( "'Hallo Welt'".matches( "'.*'" ) );          // true 
System.out.println( Pattern.matches( "'.*'", "''" ) );           // true 
System.out.println( Pattern.matches( "'.*'", "Hallo Welt" ) );   // false 
System.out.println( Pattern.matches( "'.*'", "'Hallo Welt" ) );  // false

Der Punkt im regulären Ausdruck steht für ein beliebiges Zeichen, und der folgende Stern ist ein Quantifizierer, der wahllos viele beliebige Zeichen erlaubt.

Regeln für reguläre Ausdrücke

Für reguläre Ausdrücke existiert eine ganze Menge von Regeln. Während die meisten Zeichen aus dem Alphabet erlaubt sind, besitzen Zeichen wie der Punkt, die Klammer, ein Sternchen und einige weitere Sonderfunktionen. So maskiert auch ein vorgestelltes »\« das folgende Sonderzeichen aus, was bei besonderen Zeichen wie ».« oder »\« wichtig ist.

Zunächst gilt es, die Anzahl Wiederholungen zu bestimmen. Dazu dient ein Quantifizierer (auch Wiederholungsfaktor genannt). Drei wichtige gibt es. Für eine Zeichenkette X gilt:


X?

X kommt einmal oder keinmal vor.

X*

X kommt keinmal oder beliebig oft vor.

X+

X kommt einmal oder beliebig oft vor.


Eine Sonderform ist X(?!Y) – das drückt aus, dass der reguläre Ausdruck Y dem regulären Ausdruck X nicht folgen darf. (Die API-Dokumentation spricht von »zero-width negative lookahead«.)

Listing 4.11 RegExDemo.java, main(), Ausschnitt

System.out.println( Pattern.matches( "0", "0" ) );               // true 
System.out.println( Pattern.matches( "0", "1" ) );               // false 
System.out.println( Pattern.matches( "0", "00" ) );              // false 
System.out.println( Pattern.matches( "0*", "0000" ) );           // true 
System.out.println( Pattern.matches( "0*", "01" ) );             // false 
System.out.println( Pattern.matches( "0\\*", "01" ) );           // false 
System.out.println( Pattern.matches( "0\\*", "0*" ) );           // true

Da in regulären Ausdrücken oftmals ein Bereich von Zeichen, etwa alle Buchstaben, abgedeckt werden muss, gibt es die Möglichkeit, Zeichenklassen zu definieren.


[aeiuo]

Zeichen a, e, i, o oder u

[^aeiuo]

nicht die Zeichen a, e, i, o, u

[0-9a-fA-F]

Zeichen 0, 1, 2, …, 9 oder Groß-/Klein-Buchstaben a, b, c, d, e, f


Das ›^‹ definiert negative Zeichenklassen, also Zeichen, die nicht vorkommen dürfen. Mit dem ›-‹ lässt sich ein Bereich von Zeichen angeben.

Listing 4.12 RegExDemo.java, main(), Ausschnitt

System.out.println( Pattern.matches( "[01]*", "0" ) );           // true 
System.out.println( Pattern.matches( "[01]*", "01001" ) );       // true 
System.out.println( Pattern.matches( "[0123456789]*", "112" ) ); // true

Daneben gibt es vordefinierte Zeichenklassen, die in erster Linie Schreibarbeit ersparen. Die wichtigsten sind:


.

jedes Zeichen

\d

Ziffer: [0-9]

\D

keine Ziffer: [^0-9] bzw. [^\d]

\s

Weißraum: [ \t\n\x0B\f\r]

\S

kein Weißraum: [^\s]

\w

Wortzeichen: [a-zA-Z0-9]

\W

kein Wortzeichen: [^\w]

\p{Blank}

Leerzeichen oder Tab: [ \t]

\p{Lower}, \p{Upper}

Klein-/Großbuchstabe: [a-z] bzw. [A-Z]

\p{Alpha}

Buchstabe: [\p{Lower}\p{Upper}]

\p{Alnum}

alphanumerisches Zeichen: [\p{Alpha}\p{Digit}]

\p{Punct}

Punkt-Zeichen: !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

\p{Graph}

sichtbares Zeichen: [\p{Alnum}\p{Punct}]

\p{Print}

druckbares Zeichen: [\p{Graph}]


Bei den Wortzeichen handelt es sich standardmäßig um die ASCII-Zeichen und nicht um deutsche Zeichen mit unseren Umlauten oder allgemeine Unicode-Zeichen. Eine umfassende Übersicht liefert die API-Dokumentation der Klasse java.util.regex.Pattern.

Listing 4.13 RegExDemo.java, main(), Ausschnitt

System.out.println( Pattern.matches( "\\d*", "112" ) );          // true 
System.out.println( Pattern.matches( "\\d*", "112a" ) );         // false 
System.out.println( Pattern.matches( "\\d*.", "112a" ) );        // true 
System.out.println( Pattern.matches( ".\\d*.", "x112a" ) );      // true

Galileo Computing - Zum Seitenanfang

4.6.2 Die Klassen Pattern und Matcher Zur nächsten ÜberschriftZur vorigen Überschrift

Der einfache Aufruf matches() auf einem String-Objekt beziehungsweise Pattern.matches() ist nur eine Abkürzung für die Übersetzung eines Patterns und Anwendung von matches():


String#matches()
public boolean 
matches( String regex ) 
{ 
 return Pattern.matches( regex, this ); 
}
Pattern.matches()
public static boolean 
matches( String regex,  
         CharSequence input ) 
{ 
 Pattern p = Pattern.compile( regex ); 
 Matcher m = p.matcher( input ); 
 return m.matches(); 
}

Während String’s Mitläufer-Methode matches() zur Pattern.matches() delegiert, steht hinter der statischen Fassadenfunktion Pattern.matches() die wirkliche Nutzung der beiden zentralen Klassen Pattern für das Muster und Matcher für die Mustermaschine. Für unser erstes Beispiel Pattern.matches("'.*'", "'Hallo Welt'") hätten wir also äquivalent schreiben können:

Pattern p = Pattern.compile( "'.*'" ); 
Matcher m = p.matcher( "'Hallo Welt'" ); 
boolean b = m.matches();

Hinweis Bei mehrmaliger Anwendung des gleichen Patterns sollte es compiliert gecacht werden, denn das immer wieder nötige Übersetzen über die Objektfunktion String#matches() bzw. die statische Funktion Pattern.matches() kostet Speicher und Laufzeit.



final class java.util.regex.Pattern 
implements Serializable

  • static Pattern compile( String regex ) Übersetzt den regulären Ausdruck in ein Pattern-Objekt.
  • static Pattern compile( String regex, int flags ) Übersetzt den regulären Ausdruck in ein Pattern-Objekt mit Flags. Als Flags sind CASE_INSENSITIVE, MULTILINE, DOTALL, UNICODE_CASE und CANON_EQ erlaubt.
  • int flags()
    Liefert die Flags, nach denen geprüft wird.
  • Matcher matcher( CharSequence input )
    Liefert ein Matcher-Objekt, das prüft.
  • static boolean matches( String regex, CharSequence input )
    Liefert true, wenn der reguläre Ausdruck regex auf die Eingabe passt.
  • String pattern()
    Liefert den regulären Ausdruck, den das Pattern repräsentiert.

Galileo Computing - Zum Seitenanfang

4.6.3 Quantifizierer und Wiederholungen Zur nächsten ÜberschriftZur vorigen Überschrift

Neben den Quantifizierern ? (einmal oder keinmal), * (keinmal oder beliebig oft) und + (einmal oder beliebig oft) gibt es drei weitere Quantifizierer, die es erlauben, die Anzahl eines Vorkommens genauer zu beschreiben.

  • X{n}. X muss genau n-mal vorkommen.
  • X{n,}. X kommt mindestens n-mal vor.
  • X{n,m}. X kommt mindestens n-, aber maximal m-mal vor.

Beispiel Eine E-Mail-Adresse endet mit einem Domain-Namen, der 2 oder 3 Zeichen lang ist.

static Pattern p = Pattern.compile( "[\\w|-]+@\\w[\\w|-]*\\.[a-z]{2,3}" );


Galileo Computing - Zum Seitenanfang

4.6.4 Finden und nicht matchen Zur nächsten ÜberschriftZur vorigen Überschrift

Bisher haben wir mit regulären Ausdrücken lediglich festgestellt, ob eine Zeichenfolge vollständig auf ein Muster passt. Die Matcher-Klasse kann jedoch auch feststellen, ob sich eine durch ein Muster beschriebene Teilfolge im String befindet. Dazu dient die Methode find(). Sie hat zwei Aufgaben: Zunächst sucht sie nach einer Fundstelle und gibt bei Erfolg true zurück. Das Nächste ist, dass jedes Matcher-Objekt einen Zustand mit Fundstellen besitzt, den find() aktualisiert. Einem Matcher-Objekt entlockt die Methode group() den erkannten Substring und start()/end() die Positionen. Wiederholte Aufrufe von find() setzen die Positionen weiter.

Listing 4.14 RegExAllNumbers.java, main()

String s = "'Demnach, welcher verheiratet, der tut wohl; welcher aber nicht Zeilen-Umbruch 
verheiratet, der tut besser.'" + " 1. Korinther 7, 38"; 
Matcher matcher = Pattern.compile( "\\d+" ).matcher( s ); 
while ( matcher.find() ) 
  System.out.printf( "%s an Postion [%d,%d]%n", Zeilen-Umbruch 
                      matcher.group(), matcher.start(), Zeilen-Umbruch 
                      matcher.end() );

Die Ausgabe des Zahlenfinders ist:

1 an Postion [94,95] 
7 an Postion [107,108] 
38 an Postion [110,112]

Galileo Computing - Zum Seitenanfang

4.6.5 Gierige und nicht gierige Operatoren Zur nächsten ÜberschriftZur vorigen Überschrift

Die drei Operatoren ?, * und + haben die Eigenschaft, die längste mögliche Zeichenfolge abzudecken – das nennt sich gierig (engl. greedy). Deutlich wird diese Eigenschaft bei dem Versuch, in einem HTML-String alle fett gesetzten Teile zu finden. Gesucht ist also ein Ausdruck, der im String

String string = "Echt <b>fett</b>. <b>Cool</b>!";

die Teilfolgen <b>fett</b> und <b>Cool</b> erkennt. Der erste Versuch für ein Programm:

Pattern pattern = Pattern.compile( "<b>.*</b>" ); 
Matcher matcher = pattern.matcher( string ); 
while ( matcher.find() ) 
  System.out.println( matcher.group() );

Nun ist die Ausgabe aber <b>fett</b>. <b>Cool</b>! Das verwundert nicht, denn mit dem Wissen, dass * gierig ist, passt <b>.*</b> auf die Zeichenkette vom ersten <b> bis zum letzten </b>.

Die Lösung ist der Einsatz eines nicht gierigen Operators (auch »genügsam«, »zurückhaltend«, »non-greedy«, »reluctant« genannt). In diesem Fall wird hinter dem Qualifizierer einfach ein Fragezeichen gestellt.


Gieriger Operator Nicht gieriger Operator

X?

X??

X*

X*?

X+

X+?

X{n}

X{n}?

X{n,}

X{n,}?

X{n,m}

X{n,m}?


Mit diesem nicht gierigen Operator lösen wir einfach das Fettproblem:

Listing 4.15 RegExFindBold.java, main()

Pattern pattern = Pattern.compile( "<b>.*?</b>" ); 
Matcher matcher = pattern.matcher( "Echt <b>fett</b>. <b>Cool</b>!" ); 
while ( matcher.find() ) 
  System.out.println( matcher.group() );

Wie gewünscht ist die Ausgabe:

<b>fett</b> 
<b>Cool</b>

Galileo Computing - Zum Seitenanfang

4.6.6 Mit MatchResult alle Ergebnisse einsammeln topZur vorigen Überschrift

Die Schnittstelle java.util.regex.MatchResult deklariert Operationen, die Zugriff auf das Ergebnis (String, Start-, Endposition, Anzahl Gruppen) eines Matches ermöglichen. Ein Matcher-Objekt wird dafür mit toMatchResult() nach dem MatchResult-Objekt gefragt.

Ein einfaches Beispiel verdeutlicht die Arbeitsweise: Die eigene Utility-Funktion findMatches() soll für ein Muster und eine Zeichenkette alle Ergebnisse zurückliefern.

Listing 4.16 MatchResultDemo.java, Teil 1

static Iterable<MatchResult> findMatches( String pattern, CharSequence s ) 
{ 
  List<MatchResult> results = new ArrayList<MatchResult>(); 
 
  for ( Matcher m = Pattern.compile(pattern).matcher(s); m.find(); ) 
    results.add( m.toMatchResult() ); 
 
  return results; 
}

Die Methode liefert ein einfaches Iterable zurück, was in unserem Beispiel ausreicht, um die Funktion auf der rechten Seite des Doppelpunktes vom erweiterten for nutzen zu können. Vor dem Schleifendurchlauf übersetzt compile() den Muster-String in ein Pattern-Objekt, und matcher() gibt Zugang zum konkreten Mustererkenner, also Matcher-Objekt. Die Bedingung der Schleife ist so, dass pro Durchlauf ein Muster erkannt wird. Im Rumpf der Schleife sammelt die Ergebnisliste die MatchResult-Objekte, welche die Funddaten repräsentieren. Nach Ablauf der Schleife liefert die Methode die gesammelten Objekte zurück.

Ein paar Programmzeilen zeigen schnell die Möglichkeiten. Ein einfaches Muster soll für ISBN-10-Nummern stehen – ohne Leerzeichen oder Bindestriche.

Listing 4.17 MatchResultDemo.java, Teil 2

String pattern = "\\d{9,10}[\\d|x|X]"; 
String s = "Insel: 3898425266, Reguläre Ausdrücke: 3897213494"; 
 
for ( MatchResult r : findMatches( pattern, s ) ) 
  System.out.println( r.group() + " von " + r.start() + " bis " + r.end() );

Das Ergebnis auf der Konsole ist:

3898425266 von 7 bis 17 
3897213494 von 39 bis 49

Die Informationen in einem MatchResult entsprechen also einem Zustand eines Matcher während des Parsens, genauer gesagt nach dem Erkennen einer Zeichenfolge. Daher implementiert auch die Klasse Matcher die Schnittstelle MatchResult.



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.






<< zurück
  Zum Katalog
Zum Katalog: Java ist auch eine Insel





Java ist auch eine Insel
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Tipp
Zum Katalog: Coding for Fun





 Coding for Fun


 Buchempfehlungen
Zum Katalog: Objektorientierte Programmierung





 Objektorientierte
 Programmierung


Zum Katalog: Einstieg in Eclipse 3.4






 Einstieg in
 Eclipse 3.4


Zum Katalog: Java 6 lernen mit Eclipse






 Java 6 lernen
 mit Eclipse


Zum Katalog: NetBeans Platform 6






 NetBeans
 Platform 6


Zum Katalog: Java und XML






 Java und XML


Zum Katalog: Visual C# 2008






 Visual C# 2008


Zum Katalog: IT-Handbuch für Fachinformatiker






 IT-Handbuch für
 Fachinformatiker


Zum Katalog: C++ von A bis Z






 C++ von A bis Z


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo




Copyright © Galileo Press 2009
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> 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.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de