Wieder mal Frage zu Regex

- regex
0 MudGuard
0 Nico R.
0 Gunnar Bittersmann
0 Rolf B
0 Rolf B
Guten Abend zusammen,
ich hab einen Regex, der mir alle potenziellen Beträge aus einer Zeichenkette herausfischt: preg_match_all("/[0-9,.]+/", $el, $arr)
Allerdings matcht der auch, wenn nur ,
oder .
in der Zeichenkette steht.
Ich will also erreichen, dass mindestens eine Ziffer vorkommen muss. Das hier führt leider zum gleichen Ergebnis: [0-9{1,},.]+
Sollte nicht eigentlich {1,}
oder +
genau das gewünschte besorgen?
Schöne Grüße
Nico
Hi,
ich hab einen Regex, der mir alle potenziellen Beträge aus einer Zeichenkette herausfischt:
preg_match_all("/[0-9,.]+/", $el, $arr)
Allerdings matcht der auch, wenn nur
,
oder.
in der Zeichenkette steht.Ich will also erreichen, dass mindestens eine Ziffer vorkommen muss. Das hier führt leider zum gleichen Ergebnis:
[0-9{1,},.]+
Sollte nicht eigentlich{1,}
oder+
genau das gewünschte besorgen?
Nein, innerhalb einer Zeichenklasse haben Quantifier (* + ? *? +? {n} {n,} {n,m}
) keine Wirkung.
Eine Möglichkeit wären lookarounds (positive lookahead auf eine Ziffer), eine andere, nicht nur einfach alle erlaubten Zeichen aufzulisten, sondern den Regex entsprechend der Struktur einer Zahl aufzubauen (also Vorzeichen optional, Zifferngruppen mit Tausendertrennzeichen, Bruchteiltrenner, Nachkommastellen-Zifferngruppen mit tausendstel-Trennzeichen, ggf. noch Exponent-e, Exponent-Vorzeichen, Exponent-Ziffern ...
cu,
Andreas a/k/a MudGuard
Hallo Andreas,
ja, mir ist auch eingefallen, dass ich das so ähnlich hier schonmal gefragt hatte 😖 Ich versuch mich nochmal dran...
Gruß Nico
@@MudGuard
Eine Möglichkeit wären lookarounds (positive lookahead auf eine Ziffer)
Ich hatte mal einen endlichen Automaten zur Erkennung von Kommazahlen gebaut. Auf den nächsten Slides ist zu sehen, wie er am Nachthimmel zu sehen ist (jetzt schon in der zweiten Nachthälfte, im Winter dann die ganze Nacht). Und hier mit Erklärungen von Matthias Apsel (RIP).
Wenn es einen endlichen Automaten gibt, dann gibt es auch einen regulären Ausdruck dafür. (Gemeint ist ein regulärer Ausdruck; nicht ein RegExp, was etwas anderes ist – darum ging es ja in der Präsentation.) Wir brauchen keine lookarounds – RegExp mit lookarounds sind keine regulären Ausdrücke.
eine andere, nicht nur einfach alle erlaubten Zeichen aufzulisten, sondern den Regex entsprechend der Struktur einer Zahl aufzubauen (also Vorzeichen optional, Zifferngruppen mit Tausendertrennzeichen, Bruchteiltrenner, Nachkommastellen-Zifferngruppen mit tausendstel-Trennzeichen, ggf. noch Exponent-e, Exponent-Vorzeichen, Exponent-Ziffern ...
Ja, so kriegt man das mit einem regulären Ausdruck hin.
🖖 Live long and prosper
Hallo Gunnar Bittersmann,
das haben wir vor langer Zeit mal gehabt, ja. War spannend. Aber eins ist mir unklar:
Seite 5: Dass Σ den Zeichenvorrat darstellt und a ein Zeichen daraus, darauf kann man noch kommen. Dass ∅ einen Leerstring darstellt, auch. Im Zweifelsfall liest man den Wikipedia-Artikel über reguläre Ausdrücke. Aber was stellt ε dar?! Aus meiner Sicht gehört diese Zeile da einfach nicht hin.
Rolf
@@Rolf B
das haben wir vor langer Zeit mal gehabt, ja. War spannend. Aber eins ist mir unklar:
Seite 5: Dass Σ den Zeichenvorrat darstellt und a ein Zeichen daraus, darauf kann man noch kommen. Dass ∅ einen Leerstring darstellt, auch.
∅ ist die leere Menge.
Im Zweifelsfall liest man den Wikipedia-Artikel über reguläre Ausdrücke. Aber was stellt ε dar?!
ε ist das leere Wort (Leerstring).
Im Wikipedia-Artikel steht nur was von ∅, nicht von ε. Ich muss mal das in den Referenzen in der Präsentation genannte Buch rauskramen …
Aus meiner Sicht gehört diese Zeile da einfach nicht hin.
Möglicherweise sollte man da entweder von ∅ oder von ε sprechen, aber nicht von beidem?
🖖 Live long and prosper
Hallo Gunnar Bittersmann,
aber nicht von beidem
Genau. Ansonsten müsstest Du mir bei einem Wort den Unterschied zwischen leerer Menge und leerem String erklären. Denn kenn ich nicht, deshalb hab ich ∅ auch mit Leerstring gleichgesetzt
Programmiertechnisch wäre das wohl null bzw. undefined vs "" - aber damit beschäftigt sich die theoretische Informatik weniger…
Buch rauskramen
Bei mir wäre das "Einführung in die Theoretische Informatik, Teil B". Den Kurz habe ich zwar gut bestanden, den Ordner aber längst dem Studium hinterher geschmissen (Vollzeit arbeiten, 2h pendeln und Teilzeit Info mit NF BWL studieren war mir zu viel).
Rolf
Hallo Nico,
so einfach ist das nicht. In einer Regex bedeutet ˋ[...]ˋ ein Zeichen aus einem bestimmten Zeichenvorrat. Das kann sein:
ˋ[abcxyz]ˋ bedeutet: Matche ein Zeichen, das a,b,c,x,y oder z ist
ˋ[a-z]ˋ bedeutet: Matche ein Zeichen aus dem Bereich der Zeichen von a bis z. Das geht nach ihrem Zeichencode (ursprünglich ASCII, heute Unicode),
Das kann man auch kombinieren: ˋ[a-z0-9]ˋ matcht ein Zeichen, das im Bereich a-z oder 0-9 ist.
Eine solche [] Gruppe kann mit einem Multiplikator versehen werden. ˋ[a-z]*ˋ oder ˋ[a-z]{0,}ˋ matchen beliebig viele Zeichen a-z, ˋ[a-z]+ˋ oder ˋ[a-z]{1,}ˋ matchen ein oder mehr Zeichen, ˋ[a-z]?ˋ oder ˋ[a-z]{0,1}ˋ matchen 0 oder 1 Vorkommen und allgemein matcht ˋ[a-z]{m,n}ˋ m bis n Vorkommen.
Innerhalb der eckigen Klammern hat ein Multiplikator aber keine Bedeutung, innerhalb der eckigen Klammern hast Du keine Regex-Syntax, nur die Zeichenbereich-Syntax.
Ich mutmaße, dass man deine Abfrage mit einem Lookahead oder Lookbehind lösen könnte, aber das würde ich für den falschen Ansatz halten. Denn deine Regex ist ohnehin noch zu generisch, sie würde auch "12,345,65" matchen oder "12...45". Absicht? Frage ist auch, warum Du . und , drin hast. Möchtest Du Dezimalpunkt UND Dezimalkomma treffen, oder möchtest Du auch Tausendertrennzeichen erfassen können?
Wenn wir mal nur vom Dezimalkomma reden, dann brauchst Du eine Regex, die mindestens folgende Schreibweisen versteht - das ist die Pflicht:
12345 (Nur Ziffern)
123,456 (Ein und genau ein Dezimalkomma)
Kür 1:
123.456 (auch ein und genau ein Dezimalpunkt)
Kür 2:
,543 (die Ziffern vor dem Dezimalkomma wurden weggelassen)
Kür 3:
1.234,56 (Tausendertrennzeichen)
Kür 4:
1,234.56 (englisch mit Tausenderkomma)
1'234,56 (schweizerisch)
Die Küren 1 und 4 zeigen das Hauptproblem: Zahlenformatierung ist Ländersache, und Kür 1 zeigt, wie schnell man sich um einen Faktor 1000 irren kann, wenn man im falschen Land ist. Multinationale Zahlenerkennung gelingt nur mühsam, und wusstest Du schon, dass es nach DIN auch ein Leerzeichen als Tausendertrenner gibt?
Also - bevor wir Regexe bauen - welche Kür willst Du tanzen und welche nicht?
Rolf
Hallo Rolf,
ich konnte es mit Hilfe dieses Beitrags, in dem ihr mir schonmal dazu geholfen hattet, lösen.
Ziel war es ja (eigentlich wie damals) aus einer Zeichenkette, einen Betrag herauszufischen, der folgendermaßen aussehen darf: 19
19,00
19.00
19,-
Tausendertrennzeichen gibt es nicht, es handelt sich in der Regel um Beträge unter 100. In Ausnahmefällen kann der Betrag dreistellig sein, aber vierstellig in keinem Fall. Diesen Zweck erfüllt jetzt dieser Regex:
([0-9]{0,3}([,.][0-9]{2}|[,][-])?)
Sofern ich nichts übersehen habe 🤔
Schönen Abend und besten Dank nochmal
Nico
Hallo Nico,
okay, wenn es um Geldbeträge geht, ist die Festlegung auf 2 Nachkommastellen sinnvoll und ",-" ein sinnvoller Zusatz.
Dürfte passen. Auf https://regex101.com kannst Du deine Regex gegen diversen Input testen.
Rolf
@@Nico R.
([0-9]{0,3}([,.][0-9]{2}|[,][-])?)
Sofern ich nichts übersehen habe 🤔
Doch, hast du. Sogar einiges:
Wenn danach Ziffern folgen, erlaubst du Punkt und Komma als Dezimaltrennzeichen. Wenn danach ein Strich folgt, soll nur das Komma als Dezimaltrennzeichen erlaubt sein?
Außer dem Fliegenschiss ‚-‘ (U+002D) sollte auch das richtige dafür zu verwendete Zeichen erlaubt sein: der Halbgeviertstrich ‚–‘ (U+2013). Evtl. auch der Geviertstrich, s. Abschnitt Geldbeträge.
Dein Ausdruck erlaubt auch den Leerstring; das willst du sicher nicht.
Zeicheklassen mit nur einem Zeichen machen wenig Sinn, dann kannst du gleich das Zeichen an sich notieren, d.h. ,-
anstatt [,][-]
.
🖖 Live long and prosper
Hallo Gunnar,
Sofern ich nichts übersehen habe 🤔
Doch, hast du. Sogar einiges:
Fällt mir auch gerade auf. Dazu schreibe ich demnächst nochmal...
- Wenn danach Ziffern folgen, erlaubst du Punkt und Komma als Dezimaltrennzeichen. Wenn danach ein Strich folgt, soll nur das Komma als Dezimaltrennzeichen erlaubt sein?
Ja, eigentlich schon. Das ist ja in D die übliche Abkürzung bei geraden Geldbeträgen. Ich hätte natürlich mal dazu schreiben sollen, dass es um Geldbeträge geht…
- Außer dem Fliegenschiss ‚-‘ (U+002D) sollte auch das richtige dafür zu verwendete Zeichen erlaubt sein: der Halbgeviertstrich ‚–‘ (U+2013). Evtl. auch der Geviertstrich, s. Abschnitt Geldbeträge.
Ach herrje. Guter Hinweis. Ich denke zwar, dass 98 Prozent der Nutzer, wie auch ich, den falschen Strich nutzen, einfach, weil es keine Taste für den Halbgeviertstrich gibt, aber entgegennehmen muss man den natürlich (und am besten gleich noch ein paar Belohnungskonfettis regnen lassen 🎈🎉).
- Dein Ausdruck erlaubt auch den Leerstring; das willst du sicher nicht.
An welcher Stelle denn?
Zeicheklassen mit nur einem Zeichen machen wenig Sinn, dann kannst du gleich das Zeichen an sich notieren, d.h.
,-
anstatt[,][-]
.
Ah, okay. Hab ich ersetzt.
Schöne Grüße
Nico
@@Nico R.
- Wenn danach Ziffern folgen, erlaubst du Punkt und Komma als Dezimaltrennzeichen. Wenn danach ein Strich folgt, soll nur das Komma als Dezimaltrennzeichen erlaubt sein?
Ja, eigentlich schon. Das ist ja in D die übliche Abkürzung bei geraden Geldbeträgen. Ich hätte natürlich mal dazu schreiben sollen, dass es um Geldbeträge geht…
Hast du doch? Aber vielleicht würde wirklich niemand ‚12.–‘ mit Punkt schreiben, während man ‚12.34‘ neben ‚12,34‘ zulassen sollte.
Ach herrje. Guter Hinweis. Ich denke zwar, dass 98 Prozent der Nutzer, wie auch ich, den falschen Strich nutzen, einfach, weil es keine Taste für den Halbgeviertstrich gibt,
Auf macOS ganz einfach: [⌥ option][-].
aber entgegennehmen muss man den natürlich (und am besten gleich noch ein paar Belohnungskonfettis regnen lassen 🎈🎉).
Hach, ich fühle mich wie die Goldmarie bei Frau Holle.
- Dein Ausdruck erlaubt auch den Leerstring; das willst du sicher nicht.
An welcher Stelle denn?
Vorn [0-9]{0,3}
muss keine Ziffer stehen; das Hinterteil ([,.][0-9]{2}|[,][-])?
ist optional.
🖖 Live long and prosper
Hallo Gunnar,
Vorn
[0-9]{0,3}
muss keine Ziffer stehen; das Hinterteil([,.][0-9]{2}|[,][-])?
ist optional.
Ja, aber der RegexCoach selektiert nichts, wenn ich einfach nur Leerzeichen eingebe. Beim Test mit .+
werden Leerzeichen selektiert.
Schöne Grüße
Nico
Hallo nochmal,
Sofern ich nichts übersehen habe 🤔
Doch, hast du. Sogar einiges:
Fällt mir auch gerade auf. Dazu schreibe ich demnächst nochmal...
Es gibt noch ein paar Probleme. Hier mal das erste und mein aktueller Regex:
([0-9]{0,3}([,.][0-9]{2}|,-|,–)?)
Ich habe festgestellt, dass Beträge nur selektiert werden, wenn die Zeichenkette direkt mit einer Ziffer beginnt (12,34
). Bei test 12,34
schlägt der Regex nicht mehr an. Das kann ich lösen, in dem ich den zweiten Teil nicht mit ?
optional mache:
([0-9]{0,3}([,.][0-9]{2}|,-|,–))
Dann wird auch test 12,34
oder test 12,-
gefunden. Allerdings nicht mehr 12
oder test 12
, da ja der Nachkommateil nicht mehr optional ist.
Also ist wohl doch der erste Regex der richtige Ansatz? Aber wieso findet er den Betrag nicht an einer beliebigen Stelle? Ich muss doch dafür eigentlich nichts explizit angeben, oder?
Schöne Grüße
Nico
Hi,
Es gibt noch ein paar Probleme. Hier mal das erste und mein aktueller Regex:
([0-9]{0,3}([,.][0-9]{2}|,-|,–)?)
Ich habe festgestellt, dass Beträge nur selektiert werden, wenn die Zeichenkette direkt mit einer Ziffer beginnt (
12,34
).
Versuchst Du ein match oder ein find? match setzt implizit ^ und $ an Anfang und Ende ...
cu,
Andreas a/k/a MudGuard
Hallo Andreas,
ich nutze den Ausdruck mit preg_match_all
, um alle Beträge im Suchstring einzusammeln. Spielt das für den Ausdruck an sich eine Rolle? Ich habe das Verhalten ja auch im Regex Coach.
Schöne Grüße
Nico
Hallo MudGuard,
von welcher Programmierumgebung sprichst du? PHP?
Rolf