Rolf B: RegExp-Späßchen(?)

Beitrag lesen

problematische Seite

Hallo Searcher,

Zunächst mal: da steht geschrieben „Beachten Sie: Vor der JavaScript-Version gab es noch...

Früher stand da mal "Vor der JavaScript-Version 1.5 gab es noch..." - also ECMAScript 3. Ich habe jetzt wenig Lust auf intensivere forensische Analysen, aber die AI meines geringsten Misstrauens sagt, das seien alte Netscape-Features, die vom IE und allen neueren Browsern übernommen wurden. Aktuelle Chromia kennen diese statischen Properties noch, und es gibt wohl tatsächlich ein Projekt bei TC39[1], sie als Legacy-Features neu zu standardisieren.


Von

RegExp = /(?<val_>(?<msd_>\d{1,3}(?:\.?\d{3})*?)(,(?<lsd_>\d{0,2}))?)/

rate ich übrigens dringend ab, das kann schwere Verwirrung auslösen. Wenn es wie im Screenshot ein initialisiertes static Property ist, killst Du immerhin die Konstruktorfunktion von RegExp nicht, aber ich würde die Namen bekannter globaler Funktionen nicht für eigene Properties verwenden.

Warum deine RegExp merkwürdige Dinge tut, liegt daran, dass Dein Muster keinen Ende-Delimiter für die Zahl enthält. Beachte, dass match[0] den Wert "123" hat, d.h. mehr hat er für dieses Match nicht verwendet. Du hast die .\d{3} Gruppe als nicht-gierige Wiederholung definiert, das bedeutet: er matcht sie so WENIG wie möglich. Die Dezimalgruppe ist optional, und die hast er auch ungierig übersprungen (was mich etwas wundert), und daraufhin hat er noch den Punkt übersprungen und den Rest für den zweiten Match aufbewahrt.

Mit einem Regex-Tester wie https://regex101.com/ sieht man, dass Du in Wahrheit zwei Matches hast. Den zweiten Match bekommst Du von exec aber nicht, du musst dafür ein g als Option an die Regex anhängen, und exec so lange aufrufen, bis null zurückkommt.

Forenzitat 1225 weiß seit 2008 von diesem Problem, und meine Meinung dazu wurde 2016 zu Forenzitat 2121

Was sich als Delimiter eignet, hängt von deinen Strings ab. Welche Eingaben erwartest Du, was willst Du akzeptieren, was nicht?

Warum brauchst Du den Teil vor dem ersten Tausendertrenner und die Nachkommastellen separat?

Warum zwingst Du den Anwender, Tausenderkommas zu setzen und korrekte Gruppierungen einzugeben?

Regexe, die Plausibilitäten mit prüfen sollen, muss man ankern (also ^ davor und $ dahinter), ansonsten prüfen sie nur den Teil, der plausibel ist.

Meine Empfehlung: Zuerst trimmen, dann alle Punkte rausschmeißen, dann EVENTUELL die Syntax prüfen (/^\d{1,}(,\d{0,2})?$/? - mehr nicht, ggf. maximale Stellenzahl vor dem Komma hinzufügen), und dann ganz stumpf parseFloat(input.replace(",", ".")) aufrufen.

Es sei denn, du willst gar nicht den Zahlenwert haben, sondern irgendwas anderes tun…

Rolf

--
sumpsi - posui - obstruxi

  1. https://github.com/tc39/proposal-regexp-legacy-features ↩︎