StringRegExp funktioniert fast

  • Hi Leute,
    heute schon mein 2. Post zu diesem Thema. In regulären Ausdrücken bewege ich mich noch auf Neuland. Ich würde gerne, dass er mir hieraus:

    Spoiler anzeigen

    [Section 1]
    Key1=Val1
    Key2=Val2
    Key3=Val3
    Key4=Val4
    Key5=Val5
    [Section 2]
    Key!=Val!
    Key"=Val"
    Key§=Val§
    Key$=Val$
    Key%=Val%
    [Section 3]
    KEY!=VAL!
    KEY"=VAL"
    KEY§=VAL§
    KEY$=VAL$
    KEY%=VAL%
    [Section 4]
    Key=Val
    Key9=Val9
    [Section 5]


    diesen String ausgibt, wenn ich "Section 1" eingegeben habe:

    Spoiler anzeigen

    Key1=Val1
    Key2=Val2
    Key3=Val3
    Key4=Val4
    Key5=Val5


    und zwar so, dass immer "Key=Val" in einer "Schublade" des Arrays steckt. Im Moment (script s.u.) schafft er es nur den letzten Wert, also "Key5=Val5" in das Array zu schreiben.
    Das Script sieht so aus:

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>
    $sPath = @ScriptDir & "\Ini.ini"
    $Text = FileRead($sPath)
    $sSN = "Section 1"
    $aErg42 = StringRegExp($Text, "\[" & $sSN & "\]\s(.*\s)*?\[", 3)
    If @error Then
    MsgBox(0, "", @error)
    Else
    _ArrayDisplay($aErg42)
    EndIf

    [/autoit]


    Ich hoffe ihr könnt mir helfen.
    Vielen Dank
    Aquaplant

    Einmal editiert, zuletzt von Aquaplant (11. Juli 2010 um 09:04)

  • Sowas?

    [autoit]

    $sPath = FileOpenDialog("","","All (*.*)")
    MsgBox(0,"",_IniRead("","Section 2","Key§","Default Wert"))

    [/autoit][autoit][/autoit][autoit]

    Func _IniRead($sPath, $sSection, $sKey, $sDefault)
    $aRet = StringRegExp(FileRead($sPath), '(?i)\[\Q' & $sSection & '\E]\s+(?>.+\s+)*?\Q' & $sKey & '\E\s*=\s*([^\n\r]+)', 1)
    If @error Then Return $sDefault
    Return $aRet[0]
    EndFunc ;==>_IniRead

    [/autoit]
  • @stayawayknight: Ich weiß, aber ich will ein bisschen probieren reguläre Ausdrücke draufzubekommen.
    SEuBo: Genau sowas. Die Hälfte der Ausdrücke verstehe ich (noch) nicht, ich schaus mir aber mal an.
    Ganz so falsch kann meine Idee aber doch nicht gewesen sein, wenn sie zumindest schon das letzte Element ausspuckt oder? Liegt es vielleicht daran, dass es zu gierig ist?

  • du meinst er isst alle anderen keys und values selber und teilt nur den letzten mit dir?? :D

  • Ja der frisst die, denke ich.
    Das Tutorial habe ich mir schon angesehen und verwende ich als Grundlage. Nur wenn es aus meiner Sicht richtig erscheint und es trotzdem nicht frunktioniert weiß ich logischerweise nicht, was ich falsch mache und kann mich auch dementsprechend nicht verbessern, deshalb möchte ich gerne wissen, was ich oben falsch gemacht habe und wie man es richtig macht ;)
    Vielen Dank
    Aquaplant

  • Hallo,

    Du kennst wahrscheinlich folgende nicht:
    \Q ... \E -> Metazeichen werden ignoriert. (s. Tutorial Kapitel 3.3)
    (?> ... ) -> sog. Atomic Group. Bevor ich dir jetzt das Prinzip von Atomic Groups erkläre (das wär wieder ein ganzes Tutorial Kapitel wert), merk dir einfach, dass (?> ... ) das gleiche ist wie (?: ... ), nur anders. Auf jeden Fall ist es ein nicht-fangendes-Klammerpaar.
    \r und \n sind @CR und @LF


    Schlüsseln wir dein Pattern mal auf:

    Code
    \[Section 2\]\s(.*\s)*?\[
    Code
    \[Section 2\]\s


    findet "[Section 2]" samt Zeilenumbruch

    Danach folgt

    Code
    (.*\s)*?\[


    Es wird also eine Zeile samt Zeilenumbruch gefunden. Da du aber auf das Subpattern einen * Quantifizer benutzt, wird es immer wieder überschrieben, und beinhaltet immer den letzen Satz, den es durchgegangen ist. Bis letztendlich ein [ kommt, was dann der Fall ist, wenn die nächste Section anfängt. Somit wird immer die letzte Zeile der Section ausgegeben.

  • [...] Da du aber auf das Subpattern einen * Quantifizer benutzt, wird es immer wieder überschrieben [...]

    Genau das ist noch mein Problem. Ich weiß nicht wie ich dem Quantifizer sagen soll, dass es lazy wird. In deinem Tutorial hattest du ja das ? erwähnt, um es faul zu machen. Das klappt aber leider nicht.
    Nebenbei: Das Tutorial ist super :thumbup:

    Vielen Dank für die (weitere) Hilfe
    Aquaplant

  • Nein es liegt nicht an dem Quantifizer, sondern an einem Denkfehler - das Subpattern wird so lange überschrieben, bis die nächste Zeile mit [ beginnt.
    autoit.de/wcf/attachment/10645/

    Ich bau dein Pattern jetzt nochmal Schritt für Schritt um.
    Wir beginnen mit

    Code
    \[Section 2\]


    Was ja keiner weiteren erklärung bedarf.

    Danach wollen wir alle Zeilen die zwischen der Section und dem gesuchten Key "überbrücken".
    Deine Idee mit

    Code
    \[Section 2\]\s(.*\s)*


    war schon garnicht so schlecht. Aber ändern erstmal den Klammertyp. Uns interessiert ja überhaupt nich, was in diesen Zeilen steht. Warum also in ein Subpattern wischenspeichern? Das sorgt nur für einen vollgemüllten Array den man da am Ende rausbekommt. Also ändern wir das ganze auf eine nicht fangende Klammer.

    Code
    \[Section 2\]\s(?:.*\s)*

    Danach folgt unser Suchwert. Sonst sucht dieses Pattern ja alles von [Section 2] bis zum Ende des Strings.

    Code
    \[Section 2\]\s(?:.*\s)*Key"=


    und der letzte schritt: Alles bis zum Zeilenende in ein Subpattern, und somit in ein seperates Arrayelement speichern.

    Code
    \[Section 2\]\s(?:.*\s)*Key"=(.+)

    Das wäre die Einfache Variante

    Jetzt hat man nur das Problem, dass, wenn Metazeichen im Key vorkommen, diese falsch interpretiert werden. Deswegen sollte der Key mit \Q ... \E umschlossen werden.

    Code
    \[Section 2\]\s(?:.*\s)*\QKey"=\E(.+)

    und da der Benutzer schlampig sein kann und es ggf. mal mit nem Leerzeichen einträgt:

    Code
    \[Section 2\]\s(?:.*\s)*\QKey"\E\s*=\s*(.+)