Searcher: RegExp-Späßchen(?)

problematische Seite

Zunächst mal: da steht geschrieben „Beachten Sie: Vor der JavaScript-Version gab es noch …“. (🤪 gibt es irgendwo ein JavaScript ohne Version?)

Und dann zum Späßchen: ich verwende (beispielsweise) ein RegExp = /(?<val_>(?<msd_>\d{1,3}(?:\.?\d{3})*?)(,(?<lsd_>\d{0,2}))?)/;. Wenn ich dann aber nach manchem Ergebnis suche, gibt es ein nicht gerade erwartetes undefined:

links: Quelltext; rechts: „Ergebnis“ in der Konsole

Meine Vermutung: wenn in .groups das erste Element undefined ist, dann meint die sonst eigentlich immer funktionierende Nachfrage nach den offensichtlich sehr wohl gefundenen (anderen) Elementen, die gäbe es ja garnicht. Nur wenn man explizit nach .groups.…fragt, setzt die Erinnerung dann wieder ein.

Jedenfalls: benannte Gruppen „möchten manchmal anonym sein“ …

  1. problematische Seite

    Hi,

    Zunächst mal: da steht geschrieben „Beachten Sie: Vor der JavaScript-Version gab es noch …“. (🤪 gibt es irgendwo ein JavaScript ohne Version?)

    Und dann zum Späßchen: ich verwende (beispielsweise) ein RegExp = /(?<val_>(?<msd_>\d{1,3}(?:\.?\d{3})*?)(,(?<lsd_>\d{0,2}))?)/;. Wenn ich dann aber nach manchem Ergebnis suche, gibt es ein nicht gerade erwartetes undefined:

    ich würde benannte und anonyme Gruppe (anonym ist die, die mit (, anfängt) nicht mischen. Wenn der Inhalt der Gruppe nicht gebraucht wird, dann (?:, wenn's doch gebraucht wird, dann auch einen Namen vergeben.

    links: Quelltext; rechts: „Ergebnis“ in der Konsole

    Meine Vermutung: ca. 17 Pixel im Code-Bild haben die falsche Farbe.

    (Nein, ich werde das jetzt nicht abtippen, um's zu überprüfen)

    cu,
    Andreas a/k/a MudGuard

    1. problematische Seite

      Ungefähr 17 Pixel? Was das wohl sein könnte? Eventuell ein „_“, der da als Überbleibsel manches Versuchs rund ums Problem dahinvegetierte? Der war, vorerst, ohne Bedeutung und ist jetzt auch weg.

      Ansonsten: es handelt sich ja nicht um „meine“ Farben. Die stammen „links“ vom Editor und „rechts“ von des Browsers Entwicklungsumgebung. Insofern ist „falsch“ … verwirrend.

  2. 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 ↩︎

    1. problematische Seite

      1. an der „Leiche“, dem „_“ links in static test(string) kann man noch sehen, daß ich da schon einige Experimente unternommen hatte, um an mein “missing link” doch noch heranzukommen. Da war mir gerade recht, was „irgendwie funktioniert“ hat. Aber natürlich stimmt der Einwand, denn auch so weiß man schnell (selbst) nicht, was für ein Ding man da gerade ansieht. (Sprich: das wurde geändert.)

      Und das Konstrukt? Nun, zumindest tut ein "^(?P<i>[^\d]?)(?<val_>(?P<msd_>\d{1,3}(?:.?\d{3})?)(,(?P<lsd_>\d{0,2}))?)(?P<r>[^\d]*)$" in Bbedit brav das, was ich mir gedacht hatte — die Aufrufe im Skript bekommen immer nur eine ganze „Zeile“, so daß ich da nicht auf Anfang/Ende getestet habe.

      Und nein, ich zwinge keine Anwender, ich werde gezwungen: das Skript soll mir irgendwann mal die Inhalte von gegebenen Tabellen einer Webseite in sinnvolle Inhalte wandeln. Da findet man es nämlich angebracht, beispielsweise anstelle einer „0“ (für eine Anzahl) auch mal ein „-“ oder „ungesetzt“ auszuliefern. Auch sonst ist die Zahlendarstellung da eher mit Vorsicht zu genießen, so daß ich meinen „Zahlendetektor“ dafür möglichst „störungsunempfindlich“ bauen möchte.

      Dabei bin ich dann eben über dieses „mal klappt es, mal nicht“ gestolpert und war doch „etwas überrascht“, als ich mit console.table solche wie die gezeigte fand: da sind die Gruppen anscheinend genau da, wo ich sie erwartet habe. Und trotzdem werden „meine Nachkommastellen“ im Skript nicht gefunden.

      Daß ich in solchen Fällen dann aber mit .groups.val_ doch fündig wurde … paßt auch wieder nicht zu einem „das sind zwei Ausdrücke“.

      BTW: das „Gezappel mit den Unterstrichen“ (ich habe gerade noch so einen Vagabunden gefunden) stammt übrigens daher, daß ich versucht habe, „Fipptehler“ auszumerzen: wie schnell hat man einem Objekt ein ganz neues Element (mit einem Buchstaben mehr oder weniger oder einem falschen mittendrin im Namen) eingepflanzt?

      Also habe ich es mit “computed properties” versucht. Damit sich „meine“ Speicher-Strukturen doch mehr so verhalten, wie vlt. ein C-struct oder ein Pascal record: meckern bei „Fiptelher“ ist da ja fest eingebaut.

      Aber das ist dann doch nur eine Katze (und kein Hund) geworden, die sich in den eigenen Schwanz beißt: wenn man da „den Kreis schließen“ möchte, bräuchte man plötzlich den Bezeichner, in dem die Property-Namen abgelegt wurden, als Namen für den Zugriff …

      Das Ergebnis da: es ist wieder raus …

      1. problematische Seite

        @@Searcher

        Und nein, ich zwinge keine Anwender, ich werde gezwungen: das Skript soll mir irgendwann mal die Inhalte von gegebenen Tabellen einer Webseite in sinnvolle Inhalte wandeln. Da findet man es nämlich angebracht, beispielsweise anstelle einer „0“ (für eine Anzahl) auch mal ein „-“ oder „ungesetzt“ auszuliefern. Auch sonst ist die Zahlendarstellung da eher mit Vorsicht zu genießen, so daß ich meinen „Zahlendetektor“ dafür möglichst „störungsunempfindlich“ bauen möchte.

        Zahlendetektor mit RegExp? Ganz falsches Werkzeug!

        parseInt(string) liefert dir eine Zahl, wenn in string eine auswertbare Folge von Ziffern steht, ansonsten NaN (not a number). Im letzteren Fall willst du stattdessen den Wert 0: parseInt(string) || 0 – fertig, ganz ohne RexExp.

        Was Zawinski sagt.

        🖖 Live long and prosper

        --
        In our chants of “ICE out now”
        Our city’s heart and soul persists
        Through broken glass and bloody tears
        On the streets of Minneapolis

        — Bruce Springsteen, Streets of Minneapolis
        1. problematische Seite

          Hallo Gunnar,

          Zahlendetektor mit RegExp? Ganz falsches Werkzeug!

          schrieb ich in mehr Worten letztlich schon vor eine Woche. Allerdings wollte ich da auch auf die Ursachen der Probleme eingehen, die die Regex hatte und bin erst am Ende auf deinen Punkt gekommen:

          parseInt()

          Fließkommazahlen mit parseInt()? Besser, aber immer noch das falsche Werkzeug 😉. Alles übrige steht schon im Posting vom 01.06. um 17:01 Uhr.

          Ich kann nicht verstehen, dass die Intl Library Zahlen nur per Locale formatieren, aber nicht parsen kann. Das ist doch ebenfalls ein Standardproblem.

          Rolf

          --
          sumpsi - posui - obstruxi
          1. problematische Seite

            @@Rolf B

            Fließkommazahlen

            Nein.

            mit parseInt()?

            Ja. Wie-immer-er/sie-sich-diesmal-nennt schrieb was von „Anzahl“.

            🖖 Live long and prosper

            --
            In our chants of “ICE out now”
            Our city’s heart and soul persists
            Through broken glass and bloody tears
            On the streets of Minneapolis

            — Bruce Springsteen, Streets of Minneapolis
            1. problematische Seite

              Hallo Gunnar,

              Fließkommazahlen

              Nein.

              Doch.

              In meinem Wörterbuch gibt es einen Unterschied zwischen „zum Beispiel“ und „grundsätzlich immer“.

              Da die gezeigte Regex ein Dezimalkomma verarbeiten kann (zumindest deutet sie den Wunsch an, Dezimalkommas verarbeiten zu können), kann nicht davon ausgegangen werden, dass nur Integers in den Daten vorkommen.

              Rolf

              --
              sumpsi - posui - obstruxi
              1. problematische Seite

                @@Rolf B

                Da die gezeigte Regex ein Dezimalkomma verarbeiten kann

                Du dachtest, ich hätte den/die/das[1] RegExp eines Blickes gewürdigt‽ 🤣

                🖖 Live long and prosper

                --
                In our chants of “ICE out now”
                Our city’s heart and soul persists
                Through broken glass and bloody tears
                On the streets of Minneapolis

                — Bruce Springsteen, Streets of Minneapolis

                1. Welches Genus hätten Sie denn gern? Weder weiblich wegen „Expression“ noch männlich wegen „Ausdruck“ taugt als Begründung, da RegExp ja nicht für regular expression/regulärer Ausdruck steht. ↩︎

                1. problematische Seite

                  Hallo Gunnar,

                  Welches Genus hätten Sie denn gern?

                  Das mit der Brille…

                  Weder weiblich wegen „Expression“ noch männlich wegen „Ausdruck“ taugt als Begründung

                  Aber ja doch! Exp steht definitiv für Die Expression, oder Der Ausdruck, also die oder der RegExp 🤪

                  Dass eine RegExp nicht regulär ist im Sinne der theoretischen Informatik, ändert nichts dran, dass sie ein Ausdruck für eine Grammatik ist.

                  Und Opa Noam wird dieses Jahr 98, da ist er bestimmt altersmilde genug, um einer RegExp etwas Unbeschränktheit zu gestatten (sprich: einen Ausflug in Richtung der Chomsky-Stufe 0).

                  [Backreferences können eine RegExp Engine in die Endlosschleife treiben - eine Typ 0 Grammatik kann die Turing-Maschine, die sie erkennen soll, nicht anhalten lassen, daher meine ich, dass es in Richtung der 0 geht]

                  Eine unbeschränkte RegExp wäre abgekürzt eine UrgExp. Sehr passend 🤣

                  Rolf

                  --
                  sumpsi - posui - obstruxi
              2. problematische Seite

                Hey, mitdenken? Das gilt doch nicht! 😄

                Oder: das Problem mit den sich versteckenden .groups-Elementen wurde halt von meinen „numerischen Versuchen“ gestreift. Der hier nicht weiter erwähnte Rest, der mir z.B. verraten soll (kann?), ob wir gerade eine natürliche oder eine rationale Zahl vor der Nase haben, also der dazu gehörende Kontext, läßt sich eher nicht mittels NaN erschlagen.

                Nur, um es noch mal zu verdeutlichen: Bei ein und dem selben „Ergebnis“ eines der fehlgeschlagenen Identifizierungsversuche in Browsers Inspektor nach z.B. .val_ erfolglos gefragt. Mit .groups.val_ dagegen …

  3. problematische Seite

    Hallo Searcher,

    Meine Vermutung: (...)

    ist leider haltlos. Da findet keine lazy-Initialisierung statt. Wie gesagt: Du hattest 2 Matches, weil Du non-greedy (*?) bestellt und eine Abmagerungskur bekommen hast 😉

    Rolf

    --
    sumpsi - posui - obstruxi
    1. problematische Seite

      Neben einigen anderen Dingen (z.B. die oben erwähten „vagabundierenden _“) ist auch das greedy/non-greedy ein Teil aus dem „Versuchslabor“. Auch /(?<val_>(?<msd_>\d{1,3}(?:\.?\d{3})*?)(?:,(?<lsd_>\d{0,2}))?)/ (non-capturing group!) war da ursprünglich drin. Was aber kein anders Verhalten gezeigt hat.

      Die diversen Unternehmungen sollten nur den Browser (seine JS-Maschine) zur Herausgabe von Reaktionen provozieren.

      Im Augenblick habe ich jetzt eine anscheinend funktionierende Formulierung zustande gebracht. Im Augenblick. — Mal sehen, wann mir wieder ein throw aus den Klassen-Interna um die Ohren fliegt …