Regex erkennt String nicht



  • Hi,

    warum wird folgender String von dem Regex Ausdruck nicht erkannt?

    #include <iostream>
    #include <regex>
    
    int main()
    {
        std::cout << "Correct: " << !std::regex_match("500", std::regex("[^a-zA-Z]"));
    }
    

    https://onlinegdb.com/Bykmz6c9P

    Es sollen alle Strings als inkorrekt angezeigt werden, die Nummern enthalten.

    Laut https://regex101.com/r/WiUD1i/1 sollte alles passen. C++ Regex nutzt doch ECMAScript, oder muss ich da was spezielles beachten?

    Grüße
    Leon



  • Du solltest deinen match nicht negieren, dann sollte das korrekt sein.
    Obwohl es einfachere Reguläre Ausdrücke gibt um Zahlen zu erkennen.


  • Mod

    Deine Regex guckt nur nach einem einzelnen Zeichen.



  • streich 2 ziffern und es matcht.

    Ausserdem gibts \d

    edit: sepp war schneller


  • Mod

    Zum Weiterhelfen: "\\D*" würde False sagen, wenn an irgendeiner Stelle eine Ziffer ist, und True, wenn es keine Ziffern im String gibt. Das ist was du suchst, wenn ich deine Beschreibung richtig verstehe



  • Ja er soll ja auch nur nach einem einzelnen Zeichen gucken? Sobald eine einzige Zahl in dem gesamten String vorkommt (oder auch ein "!" oder anderes), matcht er. Mit der Negierung sollte dass dann passen.

    Ich habe es so in der Datenbank geschrieben:

    CHECK(unit NOT REGEXP "[^a-zA-Z\s]|^\s*$")
    

    Sprich er checkt, dass der String nur aus Bustaben besteht und nicht leer ist (oder nur leerzeichen enthält).
    Also z.B. akzeptiert wird:
    Hello
    Hello World

    Nicht akzeptiert:
    123
    Hallo123
    (nur leerzeichen)
    Hallo?!

    Das klappt ja alles wunderbar in der Datenbank und auch entsprechend hier: https://regex101.com/r/WiUD1i/2 (Hier ist match = nicht akzeptiert ... die Negierung kommt ja dann noch hinzu).

    Meine Frage bezog sich also eher auf: Wieso klappt das in der Datenbank? Wieso klappt das mit dem regex tool? Warum klappt das nicht in C++?

    Ich will nicht ausschließen, dass mein regex ausdruck falsch ist, aber dann würde mich interessieren, warum er trotzdem im tool funktioniert.



  • Ah ich denke, ich habe verstanden, was du @SeppJ meintest.

    int main()
    {
        std::cout << "Correct: " << !std::regex_match("500", std::regex("[^a-zA-Z]+"));
    }
    

    funktioniert. Was dann übersetz heißt "Einer oder mehr".

    Ich finde es trotzdem interessant, dass sqllite und auch das tool beides akzeptieren? Habt ihr da ne Erklärung?



  • regex_match matcht den GESAMTEN String, ist also automatisch wie mit ^ ... $ eingebaut. Wenn du das nicht willst, musst du regex_search nehmen.



  • In der Doku zu std::regex_match steht:

    Determines if the regular expression e matches the entire target character sequence, which may be specified as std::string, a C-string, or an iterator pair.

    Wenn du bloss wissen willst ob das Ding irgendwo matcht, dann musst du entweder .* vorn und hinten anhängen, oder std::regex_search verwenden.

    int main()
    {
        std::cout << "Correct: " << !std::regex_match("500", std::regex("[^a-zA-Z]+"));
    }
    

    funktioniert. Was dann übersetz heißt "Einer oder mehr".

    Ich denke das macht nicht was du willst. Bei [^a-zA-Z]+ wird nur true zurückkommen wenn jedes einzelne Zeichen des Strings in der Klasse [^a-zA-Z] ist.



  • hmm okay, dann vlt. mal anders gefragt. Was wäre denn der richtige Weg? Sollte ich einfach regex_search verwenden oder stattdessen noch ein .* dranhängen?



  • @Leon0402 sagte in Regex erkennt String nicht:

    hmm okay, dann vlt. mal anders gefragt. Was wäre denn der richtige Weg? Sollte ich einfach regex_search verwenden oder stattdessen noch ein .* dranhängen?

    Was wäre denn deiner Meinung nach mehr richtig? Suchen oder kompletten Match erzwingen?


  • Mod

    Die Frage ist, was du überhaupt willst. Du schreibst zuerst

    Es sollen alle Strings als inkorrekt angezeigt werden, die Nummern enthalten.

    Aber ist für dich alles, was kein Buchstabe ist, eine Zahl? Falls du wirklich nach Ziffern prüfen möchtest, dann habe ich oben schon eine ganz kurze Lösung vorgeschlagen



  • @SeppJ er wollte wohl auch dass ein '!' gematcht wird.



  • Ich bin davon ausgegangen, dass ich einfach grundsätzlich C++ Regex nicht verstanden habe und habe entsprechend ein minimal not working Example konzipiert, so wie es empfohlen wird 😉

    Mein eigentliches Ziel ist es Einheiten zu erkennen. Also sowas wie "kg" oder auch "ein Teelöffel". Daher, was verhindert werden soll:

    • Leere Eingaben oder nur Leerzeichen
    • Zahlen
    • Irgendwelche Zeichen, die in Wörtern nicht vorkommen wie "?, !, =, )"

    Den regex, den ich dafür in sqlite benutzt habe, war

    "[^a-zA-Z\s]|^\s*$"
    

    Vermutlich habe ich da aber auch noch nicht alles bedacht. Spontan fällt mir auf, dass vermutlich "äöü" nicht zugelassen wird.



  • @Leon0402 wenn du nur Einheiten erkennen willst, warum matchst du nicht einfach nur <Zahl> <Einheit>? Zum Beispiel sowas wie ^(\d+(\.\d*)?)\s*(.+)$.



  • @eigenartig sagte in Regex erkennt String nicht:

    wenn du nur Einheiten erkennen willst, warum matchst du nicht einfach nur <Zahl> <Einheit>?

    Weil ich, wie du selbst nochmal widerholt hast, nur Einheiten matchen will 😉 Keine Zahl davor, nur die Einheit.

    Ich bin kein regex experte, aber für mich sieht es so aus als würde der Ausdruck von dir auch nicht meine (ein Post höher) beschriebenen Anforderungen erfüllen.


  • Mod

    Warum dann nicht direkt so etwas wie kg|mm|mV|…?
    Mit Abwandlungen bezüglich dessen, was davor oder danach kommen kann oder darf, da ich immer noch nicht so ganz sicher bin, was du überhaupt genau möchtest. Hier liegt ein XY-Problem vor. Was ist das, was du am Ende wirklich erreichen möchtest? Beschreib dein eigentliches Vorhaben! Nicht die Schritte, die du denkst, die dazu notwendig sind.



  • @Leon0402 wie @SeppJ bereits erwähnt würde ich versuchen eben die Einheit zu matchen und nicht alles andere als die Einheit.



  • Es geht um Einheiten, die im Bereich Kochen verwendet werden.

    Natürlich habe ich schon darüber nachgedacht, direkt Einheiten zu matchen. Allerdings gibt es sehr viele Einheiten. Von den klassischen Einheiten (g, kg, ml, l ...) zu den "umgangsprachlichen" Einheiten (Teelöffel, Esslöffel, Tasse, Priese, Packung, Stück, Messerspitze, Schuss, .... )

    Vorerst habe ich die Idee erstmal verworfen direkt nur spezifische Einheiten zuzulassen, weil es zu viele gibt und das für mich so nicht praktikabel erscheint.

    Daher die Idee im wesentlichen Freitext zu erlauben, aber eben Fälle auszuschließen, bei denen es sich garantiert um keine Einheiten handelt. Es geht also auch nur um die Eingabe einer Einheit, nix sonst.



  • @SeppJ sagte in Regex erkennt String nicht:

    kg|mm|mV|

    das kann ziemlich lang werden, wenn man von Yokto bis Yotta alle Vorsätze unterstützen will. Andererseits sind bei der Si-Basiseinheit "kg" nicht alle Vorsätze üblich.

    Also vermutlich ist es sinnvoll, per Regex nur generell auf ein paar Buchstaben zu testen, also [a-zA-Z]{1,<maxLänge>}. Wobei - was sind denn lange Einheiten? mmHg vielleicht. Aber was ist mit Einheiten wie km/h oder GeV/c^2? (das c2c^2 ist ja hier praktisch gesehen zur Einheit zugehörig!)


Log in to reply