Dynamische Variablen (Variablennamen) aus IniReadSection heraus

  • Hallo werte Community,


    ich bitte euch um Hilfe bzw. Unterstützung, da ich leider nicht mehr weiter komme. Vielleicht ist es auch einfach gar nicht möglich, belehrt mich doch bitte eines Besseren ;) .

    Problemstellung:
    Ich möchte aus einer Standard-INI-Datei die bspw. wie folgt aufgebaut ist (Achtung nur ein Beispiel)...

    [autoit]


    [Sektion1]
    Obstsorte1=Apfel
    Obstsorte2=Birne
    Augenfarbe=Grau

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

    [Sektion2]
    Key1=Value1
    Key2=Value2
    Schlüssel1=Wert1
    Schlüssel2=Wert2

    [/autoit]

    ... flexibel den Key- oder eben den Valuenamen als Variable erzeugen lassen (dynamisch eben). Hintergrund ist der, dass ich nicht für jeden einzelnen Eintrag etwa folgendes Konstrukt nutzen möchte, um den Variablennamen genauso zu benennen (bis auf das "$s" als Prefix) wie es in der INI als Key entsprechend steht.

    [autoit]


    Local $sObstsorte1 = IniRead( 'Beispiel.ini', 'Sektion1', 'Obstsorte1', '' )
    Local $sObstsorte2 = IniRead( 'Beispiel.ini', 'Sektion1', 'Obstsorte2', '' )
    Local $sAugenfarbe = IniRead( 'Beispiel.ini', 'Sektion1', 'Augenfarbe', '' )
    ...

    [/autoit]

    Mir ist bewusst, dass ich mit IniReadSection die kompellte Sektion in ein 2D Array einlesen kann und damit hätte ich auch die Werte, die ich bräuchte um die Values dann entsprechend im Programm sinnvoll zu nutzen. Mir kommt es aber auf gut lesbaren Code (CCD) an (da weitere Personen die Implementierung verstehen und upgraden müssen). Wodurch ich gern die sprechenden (dynamischen) Variablennamen nutzen würde, anstatt der Array-Konstruktion.
    Hier nochmals deutlicher:

    [autoit]


    ; bevorzugt hätte ich gern folgende Variablen dynamisch deklariert und gesetzt (aus der INI heraus zur Laufzeit)
    Local $sObstsorte1
    Local $sObstsorte2
    ...

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

    ; anstatt mit IniReadSection so was nutzen zu müssen
    Local $aSektion1[1][1]
    Local $aSektion1[2][1]
    ...

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

    ; evtl. sollte es dynamisch so angelegt sein, dass ich via For-Schleife bspw. die INI durchgehen kann und so die dynamischen Variablen; erzeugen kann, dessen Inhalt (auch aus der INI, als Value eben) ebenfalls bereits den dynamischen Variablen zugewiesen wird

    [/autoit]

    Nun vielleicht nur noch der Hinweis, dass ich mich mit Assign, Eval und Execute dazu beschäftigt habe, aber leider keinen Erfolg damit erzielen konnte. Ich bitte euch mir Tipps zu geben oder einfach eure Einschätzung ob es überhaupt machbar ist. Falls ich detailierter oder auf einen anderen Weg mein Problem bzw. Wunsch beschreiben soll, dann sagt bitte einfach Bescheid, Danke.

    Vielen Dank für etwaige Unterstützung (Ideen, Verbesserungsvorschläge, Kritik und Zustimmung).

    Einen angenehmen Tag noch!

    UserIsGrateful 【ツ】

    Einmal editiert, zuletzt von Sven-Seyfert (4. März 2016 um 08:24)

  • schau im forum mal nach dem dictionary-objekt. Das wäre eine Implementierung für eine key-value-struktur. In den aktuellen betas gibt es auch noch den eingebauten map-datentyp welcher das Selbe darstellt.

  • Du könntest über Assign und Eval arbeiten - hättest damit aber streng genommen keine wirklichen Variablen. Hier ein Beispiel aus der Hilfe:


    Mittels Assign kannst du einen beliebigen String mit einem beliebigen Datensatz abspeichern. Problematisch erscheint mir hierbei, dass du dazu gezwungen würdest, das Auslesen der Variablen ebenso dynamisch zu machen...


    AutoIt
    $aSections = IniReadSectionNames("Test.ini")
    For $j = 1 To $aSections[0]
    	$aKeyValue = IniReadSection("Test.ini", $aSections[1])
    	For $i = 1 To $aKeyValue[0][0]
    		Assign("s" & $aKeyValue[$i][0], $aKeyValue[$i][1])
    	Next
    Next
    MsgBox(64, "Augenfarbe", Eval("sAugenfarbe"))

    Hier ein Minimalbeispiel... ich bin mir allerdings nicht sicher, ob die Lösung wirklich zu deinem Problem passt, immerhin sind Arrays nicht selten deutlich "sprechender" als irgendwelche Werte die jemand aus einer Ini-Datei zieht und die dann als "falsche" Variablen praktisch im Code gehalten werden... denn an keiner Stelle - außer beim Eval am Ende, hast du wirklich den Text, wie die Variable eigentlich heißt. Das bedeutet, dass keiner - ohne die Ini-Datei aufzumachen - weiß, welche Variablen überhaupt gerade existieren.

    Mein Rat: Erstelle lieber richtige Variablen, auch wenn dir das Konstrukt nicht gefällt und es nervig ist.. ansonsten müsstest du über die Arrays arbeiten, damit es überhaupt in irgendeiner Weise verständlich für jemanden wird, der sich den Code anguckt. Denn egal ob bei Arrays oder dem Assign / Eval-Konstrukt: Du hast nie die Namen drin stehen. Und gerade für Anfänger ist letzteres deutlich komplizierter zu verstehen, als das schlichte einfache Konstrukt, dass du im Startpost genannt hast.

    Es gibt Tage, da trete ich nicht ins Fettnäpfchen. Ich falle in die Friteuse.

  • Ich würde trotzdem den IniReadSection Ansatz wählen. Warum:

    • Wenn eine neue Variable hinzukommt, dann musst Du nicht gleich das Skript anpassen
    • Einem Programmierer ist wohl schneller zu erklären, dass Du einen 2D-Array mit Name/Wert-Paaren verwendest als eine Konstruktion zur Generierung von Variablennamen
    • Setze die Ungarische Notation konsequent um, dokumentiere die Variablen noch mit Kommentar und alles ist gut
  • Nur mal als Beispiel was man mit einem Dictionary und Inis anstellen könnte:

    Einmal editiert, zuletzt von AspirinJunkie (4. März 2016 um 16:59)

  • Hallo zusammen,

    @AspirinJunkie:
    Zum Post #2 - werde mich mal mehr mit den Dict-Objects beschäfftigen, Danke für den Tipp. Zum Post #6 - ja gar nicht schlecht, coole Möglichkeiten die sich da aufbieten (aktuell jedoch nicht meine favorisierte Lösung.

    @Bioshade:
    Hatte im Post #1 erwähnt, dass ich genau eben mit Assign, Eval und Co. gearbeitet habe. Mein Ansatz war fast der Gleiche wie du ihn vorschlägst. Nur das leider auch in der Hilfe steht, dass bei Assign keine Arrays verwendet werden können. Vielen Dank aber für deinen guten Rat und deine Einschätzung zur Verwendung und Lesbarkeit! Finde auch, dass ich wahrscheinlich bei den sprechenden Namen (echten Variablen bleibe).

    @autoBert:
    Vielen Dank auch dir, dass muss ich mir mal genauer anschauen.

    @water:
    Vielen Dank dir natürlich auch. Es sind gute Argumente nur eines spricht meiner Ansicht nach stark gegen diese Variante: Was wenn in der jeweiligen Sektion ein neues Key-Value-Pair nicht unten dran sondern mitten rein eingefügt wird. Dann müsste ich alle Stellen anpassen, die von dieser Sektion betroffen sind.

    Insgesamt gesehen, vielen Dank! Habe mich noch nicht entschieden und auch noch nicht alles probiert, aber ich würde mein Feedback dazu noch geben, wenn ich einen für mich praktikablen Ansatz umgesetzt habe.


    Vielen Dank für etwaige Unterstützung (Ideen, Verbesserungsvorschläge, Kritik und Zustimmung).


    Einen angenehmen Tag noch!


    UserIsGrateful 【ツ】

  • Hallo zusammen,

    @AspirinJunkie:
    Bin gerade nochmals deinen Ansatz durchgegangen. Ja das ist eigentlich genial! Ich benenne alles sprechend und kann dann einfach die ganze Sektion in eine Variable packen, dann die nächste Sektion in eine weitere usw. Damit kann ich dann mit dem Variablennamen und dem eigentlichen INI-Key-Namen (genau wie in der INI dargestellt) eine neue Variable einsetzen, die ich dann verwende.

    Ich bereite mal ein Beispiel vor, damit alle verstehen was ich meine.

    Danke - das ist es!

    Einen angenehmen Tag noch!

    UserIsGrateful 【ツ】

  • Hallo zusammen,

    hier also die durch @AspirinJunkie angeregte, für mich praktikable, Lösung.

    INI (Beispiel.ini):

    [autoit]


    [Sektion1]
    Obstsorte1=Apfel
    Obstsorte2=Birne
    Augenfarbe=Grau
    Add1=35

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

    [Sektion2]
    Key1=Value1
    Key2=Value2
    Schlüssel1=Wert1
    Schlüssel2=Wert2
    Add2=15

    [/autoit]


    Skript:

    [autoit]


    ; ------------------------------------------------------------------------------
    ; idea: by "AspirinJunkie" (http://www.autoit.de)
    ; note: this is a version without exception handling
    ; ------------------------------------------------------------------------------
    ; read INI file in a Dictionary[Dictionary] structure
    Func _iniToDict( $sIniPath )
    Local $aIniSections = IniReadSectionNames( $sIniPath )
    Local $oDictRet = ObjCreate( 'Scripting.Dictionary' )

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

    For $i = 1 To $aIniSections[0] Step 1
    Local $oDictSec = ObjCreate( 'Scripting.Dictionary' )
    Local $aIniSection = IniReadSection( $sIniPath, $aIniSections[$i] )

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

    For $j = 1 To $aIniSection[0][0] Step 1
    $oDictSec( $aIniSection[$j][0] ) = $aIniSection[$j][1]
    Next

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

    $oDictRet( $aIniSections[$i] ) = $oDictSec
    Next

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

    Return $oDictRet
    EndFunc

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

    ; get dict
    Global $oIni = _iniToDict( 'Beispiel.ini' )

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

    ; whole section in variables
    $sSection1 = $oIni( 'Sektion1' )
    $sSection2 = $oIni( 'Sektion2' )

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

    ; example, use the values of section variables
    ConsoleWrite( $sSection1( 'Obstsorte1' ) & @CRLF )
    ConsoleWrite( $sSection1( 'Augenfarbe' ) & @CRLF )
    ConsoleWrite( $sSection2( 'Key2' ) & '|' & $sSection2( 'Schlüssel1' ) & @CRLF )
    ConsoleWrite( $sSection1( 'Add1' ) + $sSection2( 'Add2' ) & @CRLF )
    ; ------------------------------------------------------------------------------

    [/autoit]


    Damit kann ich lesbar die Variablen aus der INI sehen (als Concat-Variable) und kann sie zusätzlich genau nur dort verwenden, wo ich sie sprechend benamt verwenden möchte. Danke nochmals an @AspirinJunkie, aber auch an alle anderen.

    Damit ist der Thread für mich erledigt.

    Einen angenehmen Tag noch!

    UserIsGrateful 【ツ】