RegExp: Verschachtelte Block-Kommentare entfernen - Char nicht-in-String ersetzen

  • Hallo AspirinJunkie


    Im Thread Ausbalanzierte Stringsequenzen hast du ein RegExp Pattern gepostet, um Kommentare zu entfernen. Werden damit auch verschachtelte Block-Kommentare entfernt?


    AutoIt
    StringRegExpReplace($s_Code, '((?m)^\h*\#(?>cs|comments-start)\b(?:(?sU)(?:(?R)|.)*)^\h*\#(?>ce|comments-end)\b.+\R|(?m)^(?>(?<!")"(?>"")*.*?(?<!")"(?>"")*(?!")|(?<!'')''(?>'''')*.*?(?<!'')''(?>'''')*(?!'')|[^\;\r\n])*?\K\h*\;.*$)', '')


    Leider stürzt mein Script damit ab. Das hatte ich schon bei einem Pattern für einen anderen Zweck, und dort hat es am "\K" zu gelegen.


    Im Anhang ist ein Demo-Script, das eine Test-Datei läd und alle Kommentare entfernt entfernen sollte. Leider hängt es sich mit deinem Pattern auf und mit den anderen klappt es bei verschachtelten Kommentaren nicht zuverlässig.


    Könntest du dein Pattern so ändern, dass es auch ohne das "\K" verschachtelte Kommentare entfernt?


    Bernd.


    Edit: Thread-Titel geändert, sodass man bei einer Suche besser findet, um was es geht.

  • Leider hängt es sich mit deinem Pattern auf und mit den anderen klappt es bei verschachtelten Kommentaren nicht zuverlässig.

    Nur ein kurzer Testlauf :

    Mit dem neuen Pattern von AspirinJunkie (Beitrag #2) hängt es sich nicht mehr auf !


    Der Bereich :

    AutoIt
    ; Func TestFunctionInASingleComment()
    ; MsgBox(0, "", "Hello")
    ; EndFunc

    bleibt aber z.B. erhalten

    86598-musashi-c64-png

    "Am Anfang wurde das Universum erschaffen. Das machte viele Leute sehr wütend und wurde allenthalben als Schritt in die falsche Richtung angesehen."


  • AspirinJunkie

    Code
    (?xmi) (^\h*\# (?>cs|comments-start)\b (?sU:(?>(?R)|.)*) ^\h*\#(?>ce|comments-end)\b.*\R )

    Wow, wahnsinn! Dein Code arbeitet bisher bei kurzen Tests hervorragend. Morgen werde ich ihn auf Herz und Nieren prüfen. Wenn er hält, was er verspricht, bist du mein Held der Woche! :thumbup:


    Natürlich will ich jetzt Nachschlag. 8o Hast du vielleicht ein Pattern, das alle Vorkommen eines bestimmten Zeichens (z. B. "=") ersetzt, wenn es NICHT innerhalb von Anführungszeichen steht. Es soll ein Leerzeichen vor und hinter jedem Gleichheitszeichen eingefügt werden, das nicht in einem String-Literal steht. Beispiel:


    Dieser Text:

    Func Foo($a, $b, $sPassWort="$geheim5=_a3xyz7!?", $sPW_2='$noch=geheimer_91')

    soll hinterher so aussehen:

    Func Foo($a, $b, $sPassWort = "$geheim5=_a3xyz7!?", $sPW_2 = '$noch=geheimer_91')


    Test-Code:

    AutoIt
    Local $sTestStr = 'Func Foo($a, $b, $sPassWort="$geheim5=_a3xyz7!?", ' & "$sPW_2='$noch=geheimer_91')"
    $sTestStr = StringRegExpReplace($sTestStr, 'Zauberpattern', ' = ')
    MsgBox(0, "", $sTestStr)


    Derzeit mache ich die Erkennung an einer vorangehenden Variable fest, aber das trifft leider auch "=" Zeichen in Quotes.

    $sAllLines = StringRegExpReplace($sAllLines, '(\$\w+)\h*=\h*(\S)', '\1 = \2')


    Bernd.


    Edit: Musashi


    Sorry, hatte zu viel im Kopf. Der Bereich mit Zeilenkommentaren wird mit einem anderen Pattern ausgefiltert, ist also kein Problem. Danke fürs Testen!

  • Hast du vielleicht ein Pattern, das alle Vorkommen eines bestimmten Zeichens (z. B. "=") ersetzt, wenn es NICHT innerhalb von Anführungszeichen steht.

    Code
    (?x)( (?>"(?> [^"]+ | "" )*" | '(?> [^']+ | '' )*') (*SKIP)(*FAIL) | = )

    Bin davon ausgegangen, dass du mit Anführungszeichen AutoIt-Strings im allgemeinen meinst - also solche die durch Dopplung escaped werden.

  • Bin davon ausgegangen, dass du mit Anführungszeichen AutoIt-Strings im allgemeinen meinst - also solche die durch Dopplung escaped werden.

    Richtig gedacht und gut gemacht! Das Pattern hat auch bei weiteren Test bestanden. Ich finde das Wahnsinn, wie du das machst! :rock:Hast du ein Lager mit Pattern für alle Fälle, oder schüttelst du sowas vielleicht aus dem Ärmel? Auf jeden Fall genial und vielen Dank! :thumbup:Dafür gibts ein virutelles :theke:


    Es gibt noch den Fall, dass doppelte Gleich-Zeichen "==" NICHT als einzelne Zeichen sondern als untrennbare Einheit gesehen werden sollen. Also aus

    Func Lol123($b ="String1"=="==") soll werden:

    Func Lol123($b = "String1" == "==")

    (Das ist jetzt zwar sehr an den Haaren herbei gezogen, aber die Syntax wird von AutoIt akzeptiert.)


    Meine Versuche endeten in folgendem Workaround, aber immerhin funktionierts. :) Die erste Zeile enthält dein Pattern, ergänzt mit "|==(*SKIP)(*FAIL)" um die doppelten Gleich-Zeichen zu überspringen. Die zweite Zeile soll die doppelten Gleich-Zeichen finden und ein Leerzeichen davor und dahinter setzen. Ist das so in Ordnung, oder gibts da eine elegantere Lösung? (Die mehrfachen Leerzeichen werden im späteren Code auf jeweils 1 reduziert.)

    AutoIt
    $sAllLines = StringRegExpReplace($sAllLines, '(?x)( (?>"(?> [^"]+ | "" )*" |' & " '(?> [^']+ | '' )*') (*SKIP)(*FAIL) |==(*SKIP)(*FAIL) | = )", ' = ')
    $sAllLines = StringRegExpReplace($sAllLines, '(?x)( (?>"(?> [^"]+ | "" )*" |' & " '(?> [^']+ | '' )*') (*SKIP)(*FAIL) | == )", ' == ')

    Bernd.


    PS: Hast du vielleicht auch ein Pattern, das den Stand meines Giro-Kontos immer auffüllt, wenn Ebbe herrscht? Das wär cool! :rofl:

  • Bei meinen weiteren Bemühungen ist das rausgekommen. Ist das Mist, oder in Ordnung?

    AutoIt
    $sAllLines = StringRegExpReplace($sAllLines, _
    '(?x)( (?>"(?> [^"]+ | "" )*" |' & " '(?> [^']+ | '' )*') (*SKIP)(*FAIL) | (==) | (=) )", ' \1 ')

    Hoffentlich in Ordnung, bin ganz stolz! 8)

  • Professor Bernd

    Hat den Titel des Themas von „Verschachtelte Block-Kommentare entfernen - mit RegExp“ zu „RegExp: Verschachtelte Block-Kommentare entfernen - Char nicht-in-String ersetzen“ geändert.
  • Bei meinen weiteren Bemühungen ist das rausgekommen. Ist das Mist, oder in Ordnung?

    Wenn es funktioniert ist es immer in Ordnung.

    In dem Fall wäre die Extra-Gruppierung nicht nötig gewesen, da außen herum bereits eine Matching-Group existiert.

    Du hättest auch vor das = noch folgendes schreiben können: =?= - dann findet er 2 oder auch nur 1 = mit diesem Ausdruck (oder ={1,2}).

    Mit dem Trick kannst du das ganze auch schnell auf alle AutoIt-Operatoren erweitern:

    Code
    (?x)( (?>"(?> [^"]+ | "" )*" | '(?> [^']+ | '' )*') (*SKIP)(*FAIL) | \h* (?: [&\+\-\*\/=><]? = | [\*+\-\/&^<>?:] | <> | \b(?i:And|Or|Not)\b) \h*)

    Ich hab hierbei auch gleich die Leerzeichen drumherum mit reingenommen damit die auch gekürzt werden falls nötig.


    Hast du ein Lager mit Pattern für alle Fälle, oder schüttelst du sowas vielleicht aus dem Ärmel?

    Beides. Das Pattern für die escape-baren AutoIt-Strings hatte ich vorliegen. Und das habe ich damals auch definitiv nicht einfach so aus dem Ärmel geschüttelt. Hatte zig Varianten (vor allem mit viel Lookarounds) durchprobiert bis ich endlich bei dieser performanten Lösung gelandet bin.

    Wenn man sich den Teil vom Pattern also wegdenkt ist das Pattern ja eigentlich auch gar nicht mehr soooo kompliziert: ( ... (*SKIP)(*FAIL) | = ).

    Und das Konstrukt sagt im Grunde ja nix weiter als: Matche mir zwei Sachen: Einmal die Strings - und wenn du diese gefunden hast dann vergiss sie gleich wieder. Und nur falls du keine Strings findest dann versuche mal ob du ein = findest.

  • Das Pattern für die escape-baren AutoIt-Strings hatte ich vorliegen. Und das habe ich damals auch definitiv nicht einfach so aus dem Ärmel geschüttelt. Hatte zig Varianten (vor allem mit viel Lookarounds) durchprobiert bis ich endlich bei dieser performanten Lösung gelandet bin.

    Das kann ich mir richtig gut vorstellen! Ich habe in den letzten Tagen unzählige Web-Seiten durchgelesen und außer deinem hat nichts funktioniert. Als ich dein Pattern gesehen habe, war ich ganz aufgeregt, es sah anders aus, als alles bis dahin gefundene. Als es dann die ersten Test und dann die Härte-Tests bestanden hat, war ich begeistert! Dein Pattern ist absolut cool UND ist super schnell. Danke fürs Teilen! :thumbup:


    Du hättest auch vor das = noch folgendes schreiben können: =?= - dann findet er 2 oder auch nur 1 = mit diesem Ausdruck (oder ={1,2}).

    Prima! So langsam finde ich mich in RegExp ein. :)

    Mit dem Trick kannst du das ganze auch schnell auf alle AutoIt-Operatoren erweitern:

    Gut dass du das gepostet hast. Darüber habe ich mit alpines geredet und ich wollte die AuotIt-Operatoren ignorieren, weil zu aufwendig/kompliziert (für mich). Deine Lösung ist natürlich spitze!


    Damit kein Leerzeichen zwischen "<>" gesetzt wird, habe ich dein Patten folgendermaßen umgestellt. Oder geht es anders besser?


    (?x)( (?>"(?> [^"]+ | "" )*" | '(?> [^']+ | '' )*') (*SKIP)(*FAIL) | \h* (?: [&\+\-\*\/=><]? = | [\*+\-\/&^<>?:] | <> | \b(?i:And|Or|Not)\b) \h*)


    StringRegExpReplace($sAllLines, _

    '(?x)( (?>"(?> [^"]+ | "" )*"' & " | '(?> [^']+ | '' )*') (*SKIP)(*FAIL) | \h* (?: <> | [&\+\-\*\/=><]? = | [\*+\-\/&^<>?:] | \b(?i:And|Or|Not)\b) \h*)", ' \1 ')


    Kann man das so ändern, dass gleich die Schreibweise von "And|Or|Not" im ersetzen Text erscheint? RegExpReplace soll z. B. "or" zu "Or" machen. Ich probiere da schon eine halbe Stunde dran und kriegs nicht hin. :(


    Und auch dafür: Danke fürs Teilen! :)

  • Wenn du mit den vielen RegExen fertig bist, kannst du dann eine Art "Sammlung von RegExen zum parsen von AutoIt" veröffentlichen?

    Das kann man sicher für irgendetwas gebrauchen 8)

  • Damit kein Leerzeichen zwischen "<>" gesetzt wird, habe ich dein Patten folgendermaßen umgestellt. Oder geht es anders besser?

    Perfekt! - das war ein Fehler in meinem Pattern und genauso lässt es sich reparieren.

    Kann man das so ändern, dass gleich die Schreibweise von "And|Or|Not" im ersetzen Text erscheint? RegExpReplace soll z. B. "or" zu "Or" machen. Ich probiere da schon eine halbe Stunde dran und kriegs nicht hin. :(

    Die PCRE-Engine kann prinzipiell case conversion beim Replace (über die Parameter \U und \L).

    Damit könnte man soetwas basteln. In der AutoIt-StringRegExpReplace funktionieren die aber leider nicht :(

    Daher wäre das vernünftigste die Wörter einzeln abzufrühstücken:

    Das heißt jedoch aber nicht, dass es nicht eben doch eine unvernünftige Lösung gäbe.... :evil:

    Folgendes entstammt direkt dem Regex-Perversitätenkabinett und muss als komplett entartet bezeichnet werden:

  • Wenn du mit den vielen RegExen fertig bist, kannst du dann eine Art "Sammlung von RegExen zum parsen von AutoIt" veröffentlichen?

    Das kann man sicher für irgendetwas gebrauchen 8)

    Ich hoffe, du hast AspirinJunkie gemeint, denn meine RegExp Kenntnisse sind doch eher bescheiden. :saint:


    Perfekt! - das war ein Fehler in meinem Pattern und genauso lässt es sich reparieren.

    Juhu, ich blinder Hahn habe ein Korn gefunden! :party1:


    Die PCRE-Engine kann prinzipiell case conversion beim Replace (über die Parameter \U und \L).

    Damit könnte man soetwas basteln. In der AutoIt-StringRegExpReplace funktionieren die aber leider nicht :(

    Bestätig. Vor 5 Jahren am 2015-02-12 wurde ein Tiket dazu geöffnet und vor 4 Tagen am 2020-06-27 wurde es geschlossen, mit dem Hinweis, dass es das in AutoIt wohl auch nie geben wird. :(


    Daher wäre das vernünftigste die Wörter einzeln abzufrühstücken:

    Gute Idee.


    Folgendes entstammt direkt dem Regex-Perversitätenkabinett und muss als komplett entartet bezeichnet werden:

    Heißes Teil! Funktioniert soweit. Mal sehen, wie es sich Performance-mäßig schlägt. :)

  • Heißes Teil! Funktioniert soweit. Mal sehen, wie es sich Performance-mäßig schlägt.

    Ja, ist in der Tat ein heißes Teil... könnte man ja noch etwas perverser... so dass alle Keywords von AutoIt... :rofl:

    Wenn du mit den vielen RegExen fertig bist, kannst du dann eine Art "Sammlung von RegExen zum parsen von AutoIt" veröffentlichen?

    Das kann man sicher für irgendetwas gebrauchen

    Ja, gute Idee... und evtl. auch alle in einem Pack als Zip-Archiv. ;-)

  • Ja, ist in der Tat ein heißes Teil... funktioniert aber leider nicht bei allen Zeilen...


    Vorher: $Test = "True AND False OR NOT True"

    Nachher: $Test = "True AND False OR NOT True"

    Genau so soll es sein, alles richtig. :) Innerhalb von Quotes soll NICHT ersetzt werden.

    Wichtig: "$Test = " ist nicht der String selbst, sondern nur ein Teil des Strings, der durch StringRegExpReplace gejagt wird!

    AutoIt
    $sString = '$Test = "True AND False OR NOT True"'
    $sNeu = StringTrimRight(StringRegExpReplace($sString ...
  • aber du bist ja schneller als die Polizei erlaubt... 8o

    Das liegt daran, dass ich mich vor dem Aufräumen drücke und liebe hier poste. Meine RegExen haben sich nun über Tage chaotisch angesammelt, teilweise mit Quellen, aber auch viele, viele Tests. Aber ich werde wohl nicht drumrum kommen, denn wenn ich das nicht aufräume und dokumentiere weiß ich nächste Woche nicht mehr, was welches Pattern macht. 8o

  • Wenn du mit den vielen RegExen fertig bist, kannst du dann eine Art "Sammlung von RegExen zum parsen von AutoIt" veröffentlichen?

    Das kann man sicher für irgendetwas gebrauchen 8)

    Mars Die Sammlung von RegExp's zum Parsen von AutoIt Funktions-Köpfen ist fast fertig. Die Sammlung ist in einer Funktion gekapselt und braucht nur noch ein bisschen aufbereiten zu werden, dann kann ich sie veröffentlichen. Aber ich brauche noch einen Namen für die Funktion.


    Was die Funktion tut: Es werden alle gültigen Funktions-Köpfe aus einer Datei gelesen, dann werden die Funktions-Namen inklusive Parameter herausgefiltert und in eine übliche, aus der AutoIt Hilfe gewohnte Schreibweise formatiert.


    Wie könnte man die Funktion am besten nennen?


    "ReadFunctionHeadersFromFileAndConvertIntoEasyToReadSyntax()"

    "ReadFunctionNamesWithParamListsFromFile()"

    "ReadFunctionSyntaxesFromFile()"


    Ist alles irgendwie nicht so prickelnd. Wie kann man das besser formulieren?