Java Regex Zeichenkette validieren und zerlegen

Halus

Lt. Junior Grade
Registriert
Juli 2013
Beiträge
373
Hallo,
Ich habe hier eine Aufgabe bei der ich einfach nicht den Fehler finden kann.

Und zwar habe ich eine CSV, davon wird zeilenweise ausgelesen und einer Methode als String übergeben.
Jetzt habe ich hier verschiedene Bedingungen die erfüllt sein müssen.

Ich muss Preise validieren.

Es muss ein Blank oder Text am Anfang vorhanden sein.
Der Preis ist nicht negativ.
Die Preise bestehen aus Zahlen und einer Währung, zwischen Währung und Preis sind mehrere oder kein Blank.
Währungen sind immer groß geschrieben & nur EUR,DOLL,YEN,CHF
Nach der Währung kommt ein Blank oder Textende.

Zudem muss ich noch die Preise und deren Währungen rausextrahieren.

So, ich gehe mal einzeln sämtliche Bedingungen ab, vielleich sieht man meinen Fehler ja so einfacher.

(\\s|\\w)+ Anfangs Blank oder Text
[^-] Nicht negativ
(\\d+(\\.{1}\\d+)?) Preis
\\s* zwischen Währung und Preis ein oder mehrere Blank
(EUR|YEN|CHF|...)+ Währung
\\s+|$ Blank oder Textende nach Währung

Wenn ich jetzt zB " 40EUR " matche oder "bez 40YEN 104.3EUR" oder sonst was erhalte ich immer nur false.

Kann mir vielleicht irgendjemand verraten wo ich hier einen Fehler drin habe?
Edit:Hab ein bisschen rumgespielt und es funktioniert jetzt:)
 
Zuletzt bearbeitet:
http://www.vogella.com/tutorials/JavaRegularExpressions/article.html auch eine gute Seite.


mache am besten nicht alles auf einmal also immer nur partiell testen und dann stück für stück erweitern.

ich würde spontan sagen es liegt an dem [^-] -> es wir ein ein char erwartet was du aber nicht willst.

probiere mal
\s([0-9]+)(EUR|YEN|CHF)

edit mit punkt
\s([0-9]+)(.[0-9]+)*(EUR|YEN|CHF)
 
Zuletzt bearbeitet:
Okay, hoffe mal, dass bei dem Regexchecker nur das \ anders ist.

Genau vogella verwende ich ja auch. Und wie man oben sieht mache ich es auch Stück für Stück aber ich seh meinen Fehler einfach nicht.

Ich habs jetzt nochmal durchprobiert "124.2 EUR 45CHF "

((\d+)(.\d+)?){1} matcht 124.2
mit einem [^-] davor nur noch 24.2
Ich sehe einfach nicht woher das kommen soll.

[^-]((\d+)(.\d+)?){1}\s*(EUR|CHF) matcht auch noch 24.2 und EUR
Interessant wenn ich EUR im String weggebe matcht er noch noch von .2 bis CHF...

Mit ((\d+)(.\d+)?){1}\s*(EUR|CHF)\s* machte ich bis vor 45

(((\d+)(.\d+)?){1}\s*(EUR|CHF)\s*)* matchat alles aber gibt nur 45CHF aus, dann mache ich noch eine Klammer rum, dann sieht er mir zwar alles, allerdings gibt es mir im einzelnen nur wieder die 45CHF aus.
Warum captured der regex hier nur das letzte wenn ich keine umschließende Klammer mache?
Ich hab zwar probiert nur um die Zahl eine zusätzliche Klammer aber es wird trotzdem nur CHF ausgegeben.

Sonst jemand eine genauere Idee?
Oder warum [^-] nicht funktioniert, bzw den Nachfolgenden Ausdruck zerstört?
 
Schreib noch mal ein paar Beispieldaten auf und was genau davon gematcht werden soll. Und welchen Rückgabewert du haben willst.
 
Halus schrieb:
Ich habs jetzt nochmal durchprobiert "124.2 EUR 45CHF "

((\d+)(.\d+)?){1} matcht 124.2
mit einem [^-] davor nur noch 24.2
Ich sehe einfach nicht woher das kommen soll.


Du scheinst von [^-] etwas Falsches zu erwarten.

[^-] bedeutet, dass ZWINGEND genau ein Zeichen aus der Eigabe erkannt(besser konsumiert) werden MUSS, was nicht dem Minuszeichen entspricht.

Bei einer Eingabe 124.2 bedeutet das, dass [^-] die 1 konsumiert und ((\d+)(.\d+)?){1} dann den Rest mit 24.2 erkennt.

Also kurz:
Lass das [^-] einfach weg. Der RegEx verbietet dadurch ohnehin schon dass ein Minus an der Stelle auftauchen darf.
Ergänzung ()

Klappt folgendes evtl. für Dich? Du hast leider nicht sehr viele Beispiele gebracht, vor allem was nicht matchen darf ist auch immer sehr wichtig. Vllt. kann man den Ausdruck auch noch vereinfachen, daber das überlasse ich gerne anderen...

Hier also der RegEx:

(?:\s|(?:\w+?\s?))(\d+(?:\.\d+)?)\s*(EUR|YEN|CHF)(?:\s+|$)

Das hier erkennt jedenfalls folgende Eingaben und extrahiert über zwei capturing groups jeweils Betrag und Währung:
" 124.22EUR"
" 124.2 EUR "
"as 124.2 EUR"
" 40EUR "
"bez 40YEN"
" 124 EUR"
" 104.3EUR"
" 40 EUR "
"bez140YEN"

Ich habe jetzt nur die 3 Beispielwährungen reingebracht...müsstest du also noch erweitern.


Um den RegEx zu verstehen musst du folgende Konzepte kenne, die nicht so verbreitet sind:

Da man bei der Extraktion auf die Gruppen zugreift, muss man verhindern, ist es besser unwichtige Gruppen zu entfernen, indem man an ihren Anfang ein ?: stellt, so z.B. gleich am Anfang bei (?:\s|(?:\w+?\s?)). Das nennt man dann eine non-capturing group. Mein Ausdruck erzeugt nur 3 Gruppen. Die erste ist der gesamte gematchte String, die zweite der Betrag und die dritte die Währung.

Das \w+ am Anfang sammelt alle Buchstaben und Zahlen ein. Es "klaut" dabei natürlich auch die Ziffern vom Betrag. Damit der Ausdruck das nicht macht hängt man noch ein ? and das +. Das bedeutet dann, dass er nur so wenig Zeichen nimmt, wie notwendig, ohne den match zu gefährden.

Wenn du mit dem ganzen noch etwas spielen willst, dann kann ich Dir nur eine Seite wie z.B.
http://www.regexplanet.com/advanced/java/index.html
empfehlen. Das zeigt Dir ziemlich genau, was wovon erkannt wird.
 
So, super danke.
Ich habe nur ein wenig verändert und es geht wohl korrekt. Waren wohl wirklich die lazy Operatoren.

Nur ist das Problem, dass eben nicht alle dann "gespeichert" werden sondern nur die letzten gefunden Pattern.
Kann ich irgendwie alle gematchten erhalten?

Gibt es dann noch eine Möglichkeit einen String zu überspringen?
"45EUR asdf50.3DOL 0.5CHF

Der jetzige Pattern würde 45EUR matchen und dann abbrechen. Ich möchte die Daten aber extrahieren.
In diesem Fall möchte ich 45EUR und 0.5CHF.
Ich schätze mal sowas ist mit regex nicht möglich?
Wie mach ich dass dann am besten in Java?

Edit:
Kann es sein, dass regex101 nicht immer funktioniert?
Wenn ich ein pattern eingebe kann es vorkommen, dass dieses nicht funktioniert es umändere und später wieder in das ursprüngliche abändere und dann gehts, ohne Änderungen.

Gibt es eine Möglichkeit einen String zu begrenzen?
Ich dachte eigentlich es wäre mit {n,m} möglich aber es funktioniert nicht.
Sprich:
pattern: ([a-zA-Z0-9]*){1,11}
String: aaaaaaaaaaaaaaaaaaaaaaaaaaa
Hat definitiv mehr als elf Zeichen ist aber valide.
Oder frisst mir der Stern, diese Möglichkeit wer?
....So wie ich das sehe tut er das.
Aber wie kann ich dann pattern begrenzen, die allerdings mehrere Operatoren drin haben?
zB:
([abcd]*\.[1234}*){1,11}
Blödes Bsp aber dürfte verständlich sein.
Es dürfen beliebig viele Buchstaben und Zahlen da sein, allerdings insgesamt 11.
Doch durch die Sterne wird das elf ausgehebelt? Wie richten?
 
Zuletzt bearbeitet:
zum Begrenzen mit {1,11} solltest du das Sternchen weglassen - das steht schließlich für "beliebig viele"
 
Zurück
Oben