java-forum.org
JBoss Seam
Alter Preis: 39,95 €
Jetzt: 0,00 €

zzgl. Versandkosten

Zurück   java-forum.org > Java-Forum FAQs > FAQ - Übersicht > Java-FAQ Beiträge > Allgemeines

Thema geschlossen
Themen-Optionen Thema durchsuchen Ansicht
Alt 16.04.2005, 16:48   #1 (permalink)
Java-Forum Team
Moderator
 
Benutzerbild von Wildcard
 
Registriert seit: 10.11.2004
Beiträge: 18.262
Abgegebene Danke: 0
Erhielt 128 Danke für 126 Beiträge
Standard Grundzüge von Pattern-Matching und Split

Ein Wort vorweg:
Obwohl der StringTokenizer immer noch von vielen Programmieren verwendet wird, verzichte ich in diesem
Tutorial darauf, da er nur noch aus Gründen der Abwärtskompatibilität vorhanden ist, und generell durch
String.split() ersetzt werden sollte.

Jeder kennt das Problem, man bekommt einen Datenstring und möchte diesen jetzt in verschiedene Felder zerlegen.
Gehen wir im ersten Beispiel von einem String aus der eine Person repräsentiert und der folgenden Aufbau hat:
Vorname;Nachname;Wohnort;PLZ
Für solche einfachen 'zerlege-Aufgaben' ist die split()-Methode die einfachste Lösung.
In diesem Beispiel könnte das so aussehen:

Java Code: Quelltext in neuem Fenster öffnen
1
2
3
4
5
6
String input = "Foo;Bar;Blupp;123456"
String[] results = input.split(";");
for (int i = 0; i < results.length; i++)
{
    System.out.println(results[i]);
}
split bekommt einen Paramter der bestimmt wo der String getrennt werden soll (vorsicht, split erwartet einen 'regulären Ausdruck' als Paramter, doch dazu später mehr), und liefert ein String[] in dem die Ergebnisse stehen.
Die Ausgabe hier würde also lauten:

Foo
Bar
Blupp
123456

Wie man sieht ist split eine sehr simple Möglichkeit um einen Datenstring anhand gewisser Trennzeichen zu teilen.
Will man kompliziertere Probleme (wie Beispielsweise eine Suchfunktion bei der Wildcards erlaubt sind) lösen,
verwendet man üblicherweise Pattern-Matching.

Pattern-Matching arbeitet mit sog. regulären Ausdrücken(regular Expressions auch schlicht RegEx genannt).
RegEx sind keine Java Eigenart, sondern auch in UNIX, Perl, C#... zu finden.
Unter einem RegEx versteht man in Java einen String der sich an eine spezielle Syntax hält.
Im kompletten nachzulesen ist diese Syntax unter Pattern. Ich werde in diesem Tutorial nur auf einige dieser Funktionen eingehen.

Als erstes werden wir nun versuchen das obige split beispiel mit Pattern-Matching zu lösen.
Dafür muss erst ein Pattern erstellt werden mit dem der Eingabe-String später verglichen werden soll:
Java Code: Quelltext in neuem Fenster öffnen
1
Pattern pat = Pattern.compile("Regx");
In unserem speziellen Fall würde das so aussehen:
Java Code: Quelltext in neuem Fenster öffnen
1
Pattern pat = Pattern.compile("\\w+");
Auf den ersten Blick sieht es etwas kryptisch aus, also hier die Erklärung:
\w ist eine abkürzende Schreibweise, und steht für word-character, also das gleiche wie [A-Za-z_0-9]
(eckige Klammer bedeuten das jedes Zeichen darin erkannt wird, also würden alle Großbuchstaben von A-Z, die
Kleinbuchstaben, der '_' und die Ziffern 0-9 zu diesem Muster passen).
Warum also \\w und nicht \w ?
Der '\' ist in Java ein reserviertes Zeichen um Sonderzeichen wie 'newline', 'tabulator' usw... durch \n bzw. \t darzustellen.
Möchte man das in einem String ein ' \' steht, so muss der '\' maskiert werden => '\\'
Währe in unserem Beispiel das Trennzeichen statt des ';' ein '\' würde die Sache noch komplizierter.
Da '\' in Java und in der RegEx-Syntax als Maskierungszeichen dient, müsste dann doppelt maskiert werden:
string.split(\\\\);

Und wofür das '+'
Es gibt sog. 'greedy quantifiers' mit denen die angegeben wird wie oft ein bestimmte Zeichen auftauchen können.
'+' einmal oder beliebig oft
'*' keinmal oder beliebig oft
'?' keinmal oder einmal
Für weitere quantifieres obigem Link folgen.

So, jetzt haben wir ein Pattern, aber wie gehts weiter?
Als nächstes brauchen wir einen Matcher:
Java Code: Quelltext in neuem Fenster öffnen
1
2
Pattern pat = Pattern.compile("\\w+");
Matcher mat = pat.matcher(input);
Der Matcher wird also von unserem vorher kompilierten Pattern zurückgeliefert wenn wie dir matcher Methode mit dem input-String als Paramter aufrufen.

Der Matcher verfügt über 3 Hauptfunktionen um die Eingabe mit dem Muster zu vergleichen:

mat.matches() liefert dann true, wenn der gesamte Eingabestring zum Muster passt.

mat.find() liefert dann true wenn ein Teil der Eingabe zum Muster passt, merk sich die Ende des letzten treffers
und startet beim erneuten aufrufen von find() an dieser Position.

mat.lookingAt() liefert true wenn ein Teil der Eingabe zum Muster passt, fängt jedoch immer am Anfang der Eingabe an.
d.h. um lookingAt mehrmals verwenden zu können muss nach jedem Treffer der matcher neu erzeugt werden, da er
sonst immer die gleichen Ergebnisse liefert.

Für unseren Zweck scheint hier also mat.find() die ideale Methode:
Java Code: Quelltext in neuem Fenster öffnen
1
2
3
4
5
6
7
Pattern pat = Pattern.compile("\\w+");
Matcher mat = pat.matcher(input);
while(mat.find())
{
    //zur Bedeutung von mat.group(0) komme ich später
     System.out.println(mat.group(0));
}
Ergebnis:
Zitat:
Foo
Bar
Blupp
123456
Das Pattern sucht jetzt also den größten Teil des Strings der aus Buchstaben '_' und Zahlen besteht.

Das ist doch aber nicht das gleiche wie bei einem ';' zu trennen! Was ist mit Sonderzeichen?
Richtig! Wäre im input-String bspw. ein Name mit Umlauten würde dieses Pattern falsche Ergebnisse liefern.
Die korrekte Entsprechung für string.split(";"); müsste so aussehen:
Java Code: Quelltext in neuem Fenster öffnen
1
2
3
4
5
6
Pattern pat = Pattern.compile("[^;]+");
Matcher mat = pat.matcher(input);
while(mat.find())
{
    System.out.println(mat.group(0));
}

Wie oben beschrieben geben die '[' an, das jedes Zeichen darin erkannt wird.
'^' ist jedoch eine Negation, d.h. jetzt wird jedes Zeichen ausser ';' erkannt, was die Entsprechung von string.split(";") wäre.

Wofür soll das gut sein? Das ist ja viel komplizierter als split!!!
Komplizierter ja, aber dafür auch ungleich mächtiger, daher jetzt zur Erklärung dieser Zeile:
Java Code: Quelltext in neuem Fenster öffnen
1
System.out.println(mat.group(0));

Eine nette Funktion des Matchers ist, das er über so genannte 'capturing groups' verfügt, die beim Erstellen des RegEx definiert werden:
Java Code: Quelltext in neuem Fenster öffnen
1
2
3
4
Pattern pat = Pattern.compile("([a-zäöü]+);([a-zäöü]+);([a-zäöü]+);(\\d+)",Pattern.CASE_INSENSITIVE);
Matcher mat = pat.matcher(input);
if(mat.find())
   System.out.println(mat.group(3));

Ausgabe: "Blupp"

Alles was eingeklammert ist, stellt jetzt eine eigene Capturing-Group dar, und kann einzeln abgefragt werden.
Der matcher hat also 4 groups + die weiter oben verwendete group(0) die das Gesamtergebnis darstellt.
Zusätzlich habe ich noch Pattern.CASE_INSENSITIVE als Parameter übergeben, ich denke der Name ist selbsterklärend

Hier wird jetzt mat.matches verwendet (d.h. der gesamte String muss zum Muster passen), da jeder Datensatz diese Form haben soll.
Ein Name besteht eben nicht aus Zahlen, und in einer PLZ dürfen nur Ziffern enthalten sein.
Das ist eine Funktionalität die split nicht bieten kann.

Dieser Beitrag soll lediglich einen Einblick in die RegEx Welt liefern, um zu erkennen wie mächtig dieses package wirklich ist, ist wie so oft im Leben Eigeninitiative gefragt :###
__________________
Take back the Desktop

Geändert von L-ectron-X (28.11.2009 um 11:01 Uhr) Grund: TO umgesetzt
Wildcard ist offline  
Bei Google nach dem markiertem Wort suchen Bei Wikipedia nach dem markiertem Wort suchen Im Forum nach dem markiertem Wort suchen
Thema geschlossen

Lesezeichen

Latex Maths & Physics Editor ...

Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln
Es ist Ihnen nicht erlaubt, neue Themen zu verfassen.
Es ist Ihnen nicht erlaubt, auf Beiträge zu antworten.
Es ist Ihnen nicht erlaubt, Anhänge hochzuladen.
Es ist Ihnen nicht erlaubt, Ihre Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are aus
Pingbacks are aus
Refbacks are aus


Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
Gruppen Matching parasara Java Basics - Anfänger-Themen 14 15.10.2008 22:09
Pattern Matching Mirjam Java Basics - Anfänger-Themen 2 22.05.2008 10:02
Pattern-Matching Micha2233333 Java Basics - Anfänger-Themen 4 30.04.2006 12:33
Pattern, Matcher, Split maze2k Allgemeine Java-Themen 2 06.07.2004 22:09
pattern matching SetarLover Java Basics - Anfänger-Themen 3 30.04.2004 10:47


Alle Zeitangaben in WEZ +2. Es ist jetzt 10:07 Uhr.


Powered by vBulletin® Version 3.8.6 (Deutsch)
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.3.2
Thanks for Smilies by smilies.4-user.de