RegEx-Pattern in VBA mit anderer "Logik"?

  • Hi zusammen,
    für halbwegs normale Filter in Texten komme ich in AutoIt gut mit RegEx klar. Die Pattern sind "logisch".
    Simples zusammenstellen der Pattern und testen funktioniert HIERMIT sehr gut (für mich reichts ^^ )

    Kleinkram habe ich auch in VBA hinbekommen, aber heute wurde ich etwas überrascht.
    Ein Beispiel zum Nachvollziehen:

    Code
    123def
    www456
    abc789xyz
    1234


    Pattern zum matchen der Zahlenstrings mit voranstehenden Buchstaben: "\b[a-z]+(\d+)"
    \b Wortgrenze
    [a-z]+ wenigstens ein Buchstabe
    (\d+) Gruppe mit mindestens einer Ziffer

    AutoIt und der Regexer aus dem o.g. Link finden richtigerweise ( ?! ) die Ziffern 456 und 789

    VBA gibt mir bei identischem Pattern www456 und abc789 zurück, beachtet also die Gruppenklammern nicht!

    Erwartetes Ergebnis beim Pattern \b[a-z]+(\d+)[a-z]+ ist nicht etwa ein Treffer mit 789, sondern abc789xyz incl crlf !

    Wie überrede ich das VBA-Regex, die "richtigen" Treffer zurückzugeben bzw. die Gruppenklammern zu beachten?

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    Einmal editiert, zuletzt von Andy (11. September 2014 um 22:04)

    • Offizieller Beitrag

    Also so in etwa würde ich das lösen, am Pattern ist nichts auszusetzen (ob \d oder 0-9 ist ja egal).

    Edit: Oops, das With... vergessen ;)

  • yupp, dein Code wirft genau wie meiner als Ergebnis abc789 aus.....
    Irgendwie funzt das mit der Gruppe nicht ;(

    //EDIT oder bekommst du als Ergebnis etwa 789?

  • Hi,
    ich hole mir mit "For Each Treffer in M" alle Treffer aus dem Objekt, daran liegts nicht.
    Probier das selbst mal aus^^, hab mich jetzt auch ausgeloged und auf meinen Rechnern kein Excel/Word. Zuhause muss man sich nicht mit diesem Zeugs rumschlagen 8)

    • Offizieller Beitrag

    Jetzt fällt es mir wieder wie Schuppen aus den Haaren: Du bekommst einen Match (Item) und die Captures sind SubItem.
    So gehts:

  • Ich hatte auch mal das "Vergnügen" in Excel was in VBA zu coden, und zwar wollte ich in einer Zelle <text1> to <text2> tauschen -> <text2> to <text1> .

    Ich musste bei mehreren Zeilen erst mal den Text nach crlf splitten und die Zeilen sukzessive nach dem RegEx Pattern durchsuchen.

    Vielleicht kannst du damit was anfangen:

    Ich hatte auch damals BugFix um Hilfe geben -> danke nochmals. :thumbup: , denn mit dem VBA "gedöns" bin ich nicht so richtig vertraut.

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Sackzement! 8o
    Da muss man erst mal drauf kommen! Vielen Dank!
    Typisch Microsoft. "Logisch" wäre gewesen, die Captures zurückzugeben (wieso heissen die wohl so?! )
    Von allem was ich bisher von Regex gehört und gelesen habe, ist dieses Verhalten sogar falsch! Vor allem, weil man mit den Matches infolge nicht existenter Referenzierung garnichts anfangen kann.

    Da werde ich meine Regex-Funktion umbauen müssen, damit die richtigen Ergebnisse rauskommen. Auch toll, dass es zu diesem Theman unendlich viele FALSCHE Funktionen im Internetz gibt. Ich gehe mal davon aus, dass die Ersteller dieser Funktionen wieder mal falsch voneinander abgeschrieben haben :rolleyes:

    //Edit Eben noch einen feinen Spruch gefunden

    Zitat

    > The Microsoft VBScript Regular Expressions (5.5) object is funny at
    > best. It is hard to use, leads to lengthy code and really looks like
    > something a VB "programmer" made.

    ....wzbw

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    Einmal editiert, zuletzt von Andy (12. September 2014 um 18:41)

  • Schumi, das ist ja sehr nett, ein RegEx-Generator^^

    Bringt mir nur nichts, denn wie ich die pattern erstelle weiss ich ja. Das Problem waren lediglich die Items in den Submatches, sobald ich nach den Gruppen suche.

    Code
    If m.Item(0).SubMatches.Count > 0 Then
          Dim int1
          int1=m.Item(0).SubMatches.Item(0)
          MsgBox("("+int1+")"+"")
      End If

    jedes Mal die komplette Abfrage zu erstellen ist die Methode, die dafür wohl vorgesehen ist...imho kompletter Schwachsinn, wenn man 99% in einer Funktion RegExp(text,pattern,[parameter]) unterbringen kann!
    Denn wenn ich sowieso 15 Zeilen Code schreiben muss, kann ich das RegEx mit einer Handvoll Stringfunktionen ersetzen, welche wesentlich einfacher zu "verstehen" sind^^

    Wenn es keine Submatches gibt, dann sollen auch keine ins Ergebnis, gibt es welche, dann gehören die dort auch hin! Und nicht etwa "irgendwelche im Pattern enthaltene Matches".
    Ich werde also meine RegEx()-Funktionen so umschreiben müssen, dass wenigstens für die einfachen Pattern auch bei VBA die Ergebnisse ermittelt werden wie im PCRE & Co.

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    Einmal editiert, zuletzt von Andy (14. September 2014 um 15:22)

  • Hallo Andy,

    ja richtig, alles sehr merkwürdig.
    Ich habe mir gestern das Pattern noch einmal angesehen. Und ich hätte es anders versucht.
    Nach der Hilfe sollte das hier funktionieren.

    .Pattern = "(?:[a-z]+)\d+(?=[a-z\r\n]+)"
    Das Dumme ist nur - das funktioniert nicht - also der erste Teil! ... "(?:[a-z]+)

    Lt Hilfe:
    (?:Muster) = Entspricht Muster, speichert die Entsprechung jedoch nicht, ...

    Oder wie sollte man das deuten?

    Gruß
    Schumi

  • Ich habe zwar keine Ahnung von VB aber das beschriebene Verhalten sieht für mich nicht wirklich anders aus als das was AutoIt macht.
    Arbeitet man bei StringRegExp mit flag 2 oder 4 wird im Return[0] der globale Match und erst in den folgenden indizes die capture-groupgs (submatches) zurückgegeben.

    Der einzige wirkliche Unterschied den ich sehe ist, dass man dieses Verhalten in AutoIt über die flag einfacher ändern kann.
    Aber vom Prinzip ist das für mich nichts anderes als in VB.

  • Zitat von Schumi

    Lt Hilfe:
    (?:Muster) = Entspricht Muster, speichert die Entsprechung jedoch nicht, ...

    ja, damit hatte ich auch schon meine Probleme..."logisch" ist in dem Fall nicht, die Gruppe als nicht matchende Gruppe auszuschließen....di e Beispiele dazu sind derart krude, ich blicke da nicht durch. Wenn ich den Match nicht haben möchte bzw. nicht in einer Gruppe haben möchte, dann suche ich ihn erst garnicht...

    Zitat von AspirinJunkie

    Der einzige wirkliche Unterschied den ich sehe ist, dass man dieses Verhalten in AutoIt über die flag einfacher ändern kann.

    Mit dem Unterschied, dass es keine "offizielle" Funktion RegExp_in_VBA(text,pattern,flags) gibt!
    Lt. Hilfe ist ein Objekt zu erzeugen (nachdem vorher auch die RegEx-"Engine" 5.1 in den Extras ausgewählt und eingebunden wurde), dann die Flags bzw. Parameter nach Gusto und Anforderung zu setzen und dann die Pattern per Execute() auf den Text anzuwenden. So weit auch ok,
    Die Rückgabe erfolgt in einem weiteren Objekt, aus welchem dann, wenn man weiß wonach man sucht, das eigentliche Ergebnis weiter auseinanderklabustert bzw. zusammengesucht werden muss.
    Wenn man die Treffer bzw. Ergebnisse gerne in einem Array hätte, dann muss man diese per FOR ... IN und einem fortgesetzten REDIM dort hinein verfrachten.
    Du hast Recht, "im Prinzip" wie in AutoIt :D

  • Zitat von »Schumi«
    Lt Hilfe:
    (?:Muster) = Entspricht Muster, speichert die Entsprechung jedoch nicht, ...
    ja, damit hatte ich auch schon meine Probleme... Wenn ich den Match nicht haben möchte bzw. nicht in einer Gruppe haben möchte, dann suche ich ihn erst garnicht...

    Sorry, ich halte diese Ansicht für etwas zu kurz gedacht.
    Warum? Es kann gut sein, dass genau solch eine Bedigung (wie bei dir s.w.o) gesucht wird. Also vor den Ziffern sollen buchstaben stehen - und nur dann soll ein Treffer (nur die Ziffern) sein.
    Der Match den ich nicht haben möchte wird so zur "erweiterten Bedingung".

    In Autoit kann man das super mit zB. "(?<=[a-z])\d+(?=[a-z\r\n])" machen.
    Dieses "(?<=[a-z])" existiert aber leider nicht in VBS.

    Gruß Schumi

  • Ja, das verstehe ich, allerdings nicht, wieso ich aus dem Match die Buchstaben als Gruppe selektieren muss um danach diese Gruppe aus dem Match zu entfernen.
    Das ist sicherlich eine "unglückliche" Beschreibung, welche funktioniert.

    Wenn ich nur die Ziffern als Gruppe haben möchte, dann klammere ich diese Ziffern ein und damit ist die Gruppe der ausgewählten Ergebnisse selektiert.

    Natürlich kann ich auch den gesamten Text auswählen und alles per (?= a "ausklammern" , was ich NICHT haben möchte...."logisch" klingt für mich aber anders.

    Zitat

    Dieses "(?<=[a-z])" existiert aber leider nicht in VBS.

    irgendwo habe ich gelesen, dass das VB(A) RegEx kein lookahead (oder wars lookbehind) unterstützt.

  • ... , allerdings nicht, wieso ich aus dem Match die Buchstaben als Gruppe selektieren muss um danach diese Gruppe aus dem Match zu entfernen.
    Das ist sicherlich eine "unglückliche" Beschreibung, welche funktioniert.


    ... diese Gruppe ist bestandteil des Match. Du entfernst ja nichts. Wenn diese Gruppe nicht existiert wird nichts gefunden. Lass die Gruppe doch mal weg - wie sehen dann die Treffer aus?
    Dumm ist nur,dass das mit dem (?: nicht funktioniert. Aber...

    Evtl. hilft dir das hier. Ein kleines Tool für Autoit: http://n2b.ch/2011/01/22/autoit-regexp-tester-utility/
    Ein wirklich gutes Teil.

    In die Inputbox fügst du deinen Text ein und bei Pattern mein Regex s.w.o. . Die "Mode-Nr." (-1) steht für die Flag-Nr. aus der Funktion "StringRegExp" (s.Hilfe). Hier stell mal die 4 ein.
    Hiermit kannst du wunderbar experimentieren.

    Zitat
    irgendwo habe ich gelesen, dass das VB(A) RegEx kein lookahead (oder wars lookbehind) unterstützt.


    schau mal hier
    http://msdn.microsoft.com/en-us/library/…v=vs.84%29.aspx

    Nachtrag:
    Und schau mal ins schlaue Buch bei books.google.de
    "Regulaere Ausdruecke Kochbuch" bei "Lösung ohne Lookbehind" Seite 86
    ... alles sehr aufwändig

    Gruß Schumi

    2 Mal editiert, zuletzt von Schumi (14. September 2014 um 21:01)