Discussion:
Frage zu Regex
(zu alt für eine Antwort)
Johannes Faigle
2005-09-06 08:47:42 UTC
Permalink
Hallo.


Leider kenne ich mich mit regulären Ausdrücken noch nicht sonderlich gut
aus und habe im Internet keine Lösung gefunden, deswegen hoffe ich auf
eure Hilfe.

Folgendes Snippet:
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexTest {
public static void main(String[] args) {
Pattern p = Pattern.compile("#.*#");
Matcher m = p.matcher("abc#def#ghijkl#mn#op");
boolean b = m.find();
System.out.println(b);
System.out.println(m.group());
System.out.println(m.start());
System.out.println(m.end());
}
}

find() liefert den String #def#ghijkl#mn#. Ich möchte aber nur den
Teilstring #def# finden (und im nächsten Schritt dann #mn#).

Ist es überhaupt möglich ein Pattern zu bauen, dass mir aus dem String
nur #def# liefert? Wenn ja, wie? ("#def#" ist leider keine Lösung, weil
der Inhalt zwischen den Rauten unterschiedlich sein kann) :)

Bin für jeden Tipp dankbar.

Johannes

Ps: Vielleicht kann mir auch jemand kurz erklären warum das
größtmögliche Ergebnis gefunden wird und nicht das erste (was für mich
logischer wäre).
Oliver Haupt
2005-09-06 09:00:49 UTC
Permalink
Post by Johannes Faigle
Hallo.
Leider kenne ich mich mit regulären Ausdrücken noch nicht sonderlich gut
aus und habe im Internet keine Lösung gefunden, deswegen hoffe ich auf
eure Hilfe.
[...]
Post by Johannes Faigle
find() liefert den String #def#ghijkl#mn#. Ich möchte aber nur den
Teilstring #def# finden (und im nächsten Schritt dann #mn#).
Du hats ja auch einen Ausdruch definiert, der sagt:
"Passt auf zwei # mit beliebigem Inhalt dazwischen."

Das hast Du auch bekommen ;)
Post by Johannes Faigle
Ist es überhaupt möglich ein Pattern zu bauen, dass mir aus dem String
nur #def# liefert? Wenn ja, wie? ("#def#" ist leider keine Lösung, weil
der Inhalt zwischen den Rauten unterschiedlich sein kann) :)
Du solltest schon abstrakt definieren koennen was Du moechtest. Dieses
Schema bildest Du dann in einem RegExp ab.

Frage ist also: Warum moechtest Du #def# und nicht #zzz#?
Post by Johannes Faigle
Bin für jeden Tipp dankbar.
Nimm keine matcher oder sogar keine RegExp.

In deinem Fall waere sowas wie

String.split( '#' ) oder sogar ein StringTokenizer sinnvoller.
Post by Johannes Faigle
Ps: Vielleicht kann mir auch jemand kurz erklären warum das
größtmögliche Ergebnis gefunden wird und nicht das erste (was für mich
logischer wäre).
Es wird halt der erste Treffer geliefert. Das ist in Deinem Fall alles
was zwischen dem Ersten und dem Letzten '#' steht.

Google mal nach 'regexp test online' da solltest Du ne Seite mit nem
Applet finden, das regExp 'on the fly' gegen Strings ballert. Ist fein
zum Testen.

cu,

olli
Johannes Faigle
2005-09-06 09:32:52 UTC
Permalink
Post by Oliver Haupt
Post by Johannes Faigle
find() liefert den String #def#ghijkl#mn#. Ich möchte aber nur den
Teilstring #def# finden (und im nächsten Schritt dann #mn#).
"Passt auf zwei # mit beliebigem Inhalt dazwischen."
Das hast Du auch bekommen ;)
Ich weiß. :)
Post by Oliver Haupt
Post by Johannes Faigle
Ist es überhaupt möglich ein Pattern zu bauen, dass mir aus dem String
nur #def# liefert? Wenn ja, wie? ("#def#" ist leider keine Lösung, weil
der Inhalt zwischen den Rauten unterschiedlich sein kann) :)
Du solltest schon abstrakt definieren koennen was Du moechtest. Dieses
Schema bildest Du dann in einem RegExp ab.
Frage ist also: Warum moechtest Du #def# und nicht #zzz#?
Entschuldigung, ist vielleicht ein blödes Beispiel. Ich möchte ein
Pattern, dass mir einen Teilstring der von einer Raute bis zur
_nächsten_ Raute geht (nicht bis zur letzten Raute, wie bei #.*#).
Post by Oliver Haupt
Post by Johannes Faigle
Bin für jeden Tipp dankbar.
Nimm keine matcher oder sogar keine RegExp.
In deinem Fall waere sowas wie
String.split( '#' ) oder sogar ein StringTokenizer sinnvoller.
Das ganze wird noch ein Stück komplizierter und wäre zb mit
StringTokenizern wahrscheinlich weniger sauber lösbar.

danke
Johannes
Oliver Haupt
2005-09-06 10:02:40 UTC
Permalink
Post by Johannes Faigle
Entschuldigung, ist vielleicht ein blödes Beispiel. Ich möchte ein
Pattern, dass mir einen Teilstring der von einer Raute bis zur
_nächsten_ Raute geht (nicht bis zur letzten Raute, wie bei #.*#).
Ich tendiere dann eher zu String#split( String ), ist einfacher
anzuwenden und regexp kann man ebenfalls verwenden.
Post by Johannes Faigle
Post by Oliver Haupt
Nimm keine matcher oder sogar keine RegExp.
In deinem Fall waere sowas wie
String.split( '#' ) oder sogar ein StringTokenizer sinnvoller.
Das ganze wird noch ein Stück komplizierter und wäre zb mit
StringTokenizern wahrscheinlich weniger sauber lösbar.
Kann gut sein ;) Nur wird - IMO - zu oft zu regexp gegriffen. Diese
sind extrem maechtig, je nachdem wie sie angewandt werden (und vor
allem wie oft) drueckt's ein wenig auf die Bremse.
Und kompliziertere Ausdruecke machen wenn man Sie laenger nicht mehr
benutzt hat viel Spass. Man kann damit gut die verstaendlichkeit von
Programmen effizient reduzieren ;)

cu,

olli
Ralf Ullrich
2005-09-06 12:30:18 UTC
Permalink
Post by Oliver Haupt
Ich tendiere dann eher zu String#split( String ), ist einfacher
anzuwenden und regexp kann man ebenfalls verwenden.
Hast du mal in den Code von String.split geschaut?

public String[] split(String regex, int limit) {
return Pattern.compile(regex).split(this, limit);
}
Post by Oliver Haupt
Kann gut sein ;) Nur wird - IMO - zu oft zu regexp gegriffen. Diese
sind extrem maechtig, je nachdem wie sie angewandt werden (und vor
allem wie oft) drueckt's ein wenig auf die Bremse.
Ehrlich gesagt ist String.split mit einem _konstanten_ Pattern langsamer als z.B. dieser Code:

// a field
Pattern lazyPattern;

// replacement for s.split("....", limit):
if (lazyPattern == null) {
lazyPattern = Pattern.compile("....");
}
String[] result = lazyPattern.split(s, limit);

Wenn einem also die Performance _wirklich_ Sorgen macht (und vorher sollte man eigentlich nicht
versuchen zu optimieren), dann ist "s.split()" statt Pattern/Matcher sicher die falsche Strategie.

cu
Oliver Haupt
2005-09-06 14:03:59 UTC
Permalink
Post by Ralf Ullrich
Post by Oliver Haupt
Ich tendiere dann eher zu String#split( String ), ist einfacher
anzuwenden und regexp kann man ebenfalls verwenden.
Hast du mal in den Code von String.split geschaut?
public String[] split(String regex, int limit) {
return Pattern.compile(regex).split(this, limit);
}
Welch Ueberraschung *eg*

Ich schrieb ja auch: '... und regexp kannst Du ebenfalls verwenden.'

War vielleicht missverstaendlich ausgedrueckt ;)
Post by Ralf Ullrich
Wenn einem also die Performance _wirklich_ Sorgen macht (und vorher sollte man eigentlich nicht
versuchen zu optimieren), dann ist "s.split()" statt Pattern/Matcher sicher die falsche Strategie.
Naja, der Hauptgrund die String#split zu nehmen ist bei mir wenn
persoenliche Faulheit - ist teilweise schneller zu tippen als ein
StringTokenizer.

Wenn man sich schon Gedanken ueber die Performance macht, wird man
sicherlich eine elegante Loesung finden.
Ich habe halt manchmal das Gefuehl, dass regexp schnell uebertrieben
eingesetzt werden. Ich versuche regulaere Ausdruecke zu vermeiden -
ausser man benoetigt diese explizit. Zum Beispiel aufgrund eines
komplexen Problems, haeufiger Anwendung oder sonstwas.

Ausserdem muss man unter 1.3.1 immer noch das ORO jar benutzen :(
.
.
.
Ja, Oracle 9.x unterstuetzt nur das JDK 1.3.1 - leider.


cu,

olli
Ralf Ullrich
2005-09-06 15:18:47 UTC
Permalink
Post by Oliver Haupt
Naja, der Hauptgrund die String#split zu nehmen ist bei mir wenn
persoenliche Faulheit - ist teilweise schneller zu tippen als ein
StringTokenizer.
Nur das wir uns nicht missverstehen: Ich habe nichts dagegen s.split() zu verwenden, ganz im
Gegenteil, es ist definitiv schneller getippt und lesbarer. Mich hat nur gestört, dass es sich in
deinem vorherigen Post so angehört hat, als ob man RegExp wegen der Performance _nicht_ nehmen solle
aber dafür split() oder Tokenizer. Und dafür mag es sicher auch Gründe geben, aber Performance ist
es i.d.R. nicht.

cu
Sascha Broich
2005-09-06 09:10:50 UTC
Permalink
Post by Johannes Faigle
Hallo.
Leider kenne ich mich mit regulären Ausdrücken noch nicht sonderlich gut
aus und habe im Internet keine Lösung gefunden, deswegen hoffe ich auf
eure Hilfe.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexTest {
public static void main(String[] args) {
Pattern p = Pattern.compile("#.*#");
Matcher m = p.matcher("abc#def#ghijkl#mn#op");
boolean b = m.find();
System.out.println(b);
System.out.println(m.group());
System.out.println(m.start());
System.out.println(m.end());
}
}
find() liefert den String #def#ghijkl#mn#. Ich möchte aber nur den
Teilstring #def# finden (und im nächsten Schritt dann #mn#).
Dann sollte deine Regex das auch ausdrücken:
"#[^#]+#"
= # gefolgt von mindestens einem _anderen_ Zeichen gefolgt von #

Alternativ solltest du String.split("#") verwenden, das liefert dir die
Elemente zwischen den # als String-Array.


Sascha Broich
--
Früher war alles besser.
Aber dann wurden die Pyramiden gebaut.
Johannes Faigle
2005-09-06 09:35:13 UTC
Permalink
Hallo Sascha.
Post by Sascha Broich
"#[^#]+#"
= # gefolgt von mindestens einem _anderen_ Zeichen gefolgt von #
Danke, genau das ist es!

mfg
Johannes
Markus Schönhaber
2005-09-06 09:49:44 UTC
Permalink
Post by Johannes Faigle
Hallo Sascha.
Post by Sascha Broich
"#[^#]+#"
= # gefolgt von mindestens einem _anderen_ Zeichen gefolgt von #
Danke, genau das ist es!
Alternativ kannst Du den "*" non-greedy machen, also dafür sorgen, daß ".*"
möglichst wenige Zeichen matcht und nicht - wie sonst - möglichst viele:

"#.*?#"

Gruß
mks
Ralf Ullrich
2005-09-06 12:00:18 UTC
Permalink
Post by Johannes Faigle
Pattern p = Pattern.compile("#.*#");
Matcher m = p.matcher("abc#def#ghijkl#mn#op");
@see java.util.regex.Pattern : Suche nach Greedy und Reluctant

Greedy: "#.*#" auf "abc#def#ghijkl#mn#op" liefert "#def#ghijkl#mn#"

Reluctant: "#.*?" auf "abc#def#ghijkl#mn#op" liefert "#def#" und "#mn#"

Oder anders:

Greedy liefert die längste mögliche Sequenz, die auf das Pattern passt.

Reluctant liefert die kürzeste mögliche Sequenz, die auf das Pattern passt.

cu
Johannes Faigle
2005-09-06 15:55:56 UTC
Permalink
Hallo Ralf und Markus!

Die Lösung mit #.*?# funktioniert auch wunderbar. Danke für euren
Hinweis und die Erklärung.

Johannes

Loading...