Beiträge von AspirinJunkie

    Wow - wirklich klasse Ding :thumbup:


    Ein paar Fragen / Anmerkungen dazu:

    So wie ich das verstehe, ist ein direkter Zugriff auf die nativen AutoIt-Objekte selbst nicht vorgesehen (bzw. noch keine Funktion hierfür implementiert)?
    Also der Zugriff auf diese soll ausschließlich über die Funktionen der UDF erfolgen?
    Eigene Anpassungen der Controls sind damit also nicht möglich?

    Z. B. möchte ich einen Baloon-Tip auf einen Button setzen. In der XML-Struktur gibt es bislang keine Funktionalität hierfür und eine Funktion welche mir von einem der Elemente aus der XML-Struktur die Control-ID zurückgibt, habe ich auch nicht.

    Wenn du hier noch ein Möglichkeit schaffen würdest auf die darunterliegenden AutoIt-eigenen-Elemente zuzugreifen würde dies die Flexibilität und Einsatzmöglichkeiten wohl deutlich erhöhen.


    Du hast eine Pure-Basic-Dll als XML-Wrapper verwendet. Die Abhängigkeit zu dieser dll (die hier nur in 32Bit vorliegt und damit 64-Bit-Programme verhindert) ist sicher verschmerzbar aber eine Alternative wäre ja das Microsoft.XMLDom-Objekt gewesen welches ja bereits in Windows enthalten ist. Gibt es einen bestimmten Grund warum du den Pure-Basic-Wrapper bevorzugt hast?


    Zu der XML/JSON: Diskussion:
    Ne - XML ist schon die richtige Sprache dafür. Bisherige Formate für GUIs (Mozillas XUL, Microsofts XAML, das UI-Format vom Qt-Designer und und und) sind nicht ohne Grund XML-basiert.

    JSON kann zwar die Verschachtelung darstellen und damit die hierarchische Beziehung der Elemente gut abbilden, aber es existiert keine syntaktische Trennung von Elementattributen und Elementinhalt.

    Das müsste man über speziell benannte Attribute machen die schon optisch auf der selben Ebene stehen wie die Attribute des Elementes selbst.


    Wenn man es mit XML dann weiter treibt, kann man mit XSD die Struktur bis ins kleinste Detail festzurren so dass Abweichungen/Fehler gleich beim Parsen erkannt werden können (das geht sogar soweit, dass Wertebereiche für Values angegeben werden können und so weiter). In JSON müssten diese Checks wieder mit in den Programmcode und würden den entsprechend aufblähen (ja ich weiß es gibt JSON-Schema - aber mir ist kein in AutoIt verwendbarer Parser hierfür bekannt).

    Also XML ist schon die vernünftigste Wahl hierzu.

    Neue Version hab ich hochgestellt.


    Deine xlsx hat Zellen die keinen Inhalt haben aber einen Style besitzen.

    Für die Ausgabe als Array sollten die also ignoriert werden.
    Nun ist es jedoch so, dass die UDF zwei Wege hat die Ausmaße des Arrays zu bestimmen.

    Zum einen schaut sie ob ein dimension tag existiert, denn dort trägt Excel ein bis wohin die beschriebenen Zellen gehen.

    Problem hierbei: Gestylte, aber leere Zellen werden hier mit reingezählt.

    Wenn kein solches Tag existiert geht die UDF einfach alle Zellen durch und schaut wo das jeweilige Maximum liegt.
    In deinem Fall wäre diese Vorgehensweise aber meiner Meinung nach besser da du sonst am Ende noch einige leere Zeilen hast.


    Vielleicht sollte ich daher prinzipiell auf die Auswertung des dimension-tag verzichten?


    Vielleicht auch und statt oder? ;)

    Ja hab es natürlich mit ergänzt.


    Edit: Ach hab es jetzt einfach komplett auf die empirische Bestimmung der Dimension umgestellt.
    Der dimension-tag ist nun draußen.

    In Verbindung mit den neuen Zeilenauswahlparametern kann man übrigens Headerzeilen und sowas ignorieren.

    Bei deiner Testdatei z.B könnte daher folgendes die Weiterverarbeitung wohl vereinfachen: _xlsx_2Array("text.xlsx", 1, 5)


    Edit 2: Ach und weil ich gerade sehe, dass du Datumswerte mit drin hast - die kannst du im Nachhinein mit der bereits enthaltenen aber etwas versteckten Funktion __xlsxExcel2Date() in ein normales Datum umrechnen.

    Ich musste letztens xlsx-Dateien einlesen und mochte die Variante über Excel.au3 nicht wirklich, da diese durch Excel selbst ziemlichen Overhead hat und außerdem ist man darauf angewiesen dass Excel auch installiert ist. Also hab ich mir mal so eine xlsx-Datei näher angesehen und daraufhin eine kleine Funktion geschrieben, welche mir direkt mit Bordmitteln ein Worksheet aus der Datei in ein Array einliest.


    Das ganze ist jetzt nicht wahnsinnig auf alle Spezialfälle hin ausgebaut sondern deckt bislang die Fälle ab, welche bei mir bisher aufgetreten sind. Es gibt wohl auch schon andere UDFs die das gleiche machen aber selbst machen, macht mehr Spaß!


    Da die xlsx-Dateien entpackt werden müssen empfehle ich eine >>7za.exe<< mit zum Skript dazuzupacken, sonst wird auf die Shell.Application-Methode ausgewichen und die ist laaaaaaangsam...


    Große Erklärung ist nicht notwendig:

    AutoIt
    #include <Array.au3>
    #include "xlsxNative.au3"
    Global $aWorksheet = _xlsx_2Array("Test.xlsx", 1)
    _ArrayDisplay($aWorksheet)

    Changelog:

    2020/08/07 __xlsxExcel2Date: Stringausgabe (lokal formatiert) der Datums/Zeit-Werte implementiert
    2020/07/31

    Fix: Zellen mit hybriden Zellinhalten wurden ignoriert


    Leere aber gestylte Zellen werden nicht mehr prozessiert (Leerzeilen werden vermieden und etwas schneller)

    2020/07/30 Verbesserung der Namespace-Behandlung
    2020/07/29 Parameter um auf bestimmte Zeilen einzugrenzen hinzugefügt

    Dateien

    • xlsxNative.au3

      (13,28 kB, 3 Mal heruntergeladen, zuletzt: )

    Kann man die Suche nach unbalancierten Quotes so begrenzen, dass sie nur innerhalb 1 Zeile gewertet werden?

    Klar:

    Code
    (?mi)^\h*Func\h+((?(DEFINE)(?<brackets>\((?|''(?>[^''\v]+|'''')*''|"(?>[^"\v]+|"")*"|[^\(\)\r\n"'']*|(?&brackets))*\)))\w+\h*(?&brackets)\h*(?=\R\h*EndFunc))

    Edit: Evtl. wichtig dazu zu sagen: Das ist das Pattern für den String in AutoIt, da die Hochkommas bereits esaped sind.

    Als erstes: Meine Erklärung war falsch da ich mal wieder lookbehind mit lookahead verwechselt habe.
    Das (?=...) ist das positive lookahead!


    Streng genommen schaut es ob an der aktuellen Stelle noch das direkt folgt was du im lookahead angibst.

    Also das was davor steht wird nur gematcht wenn das dahinter folgt.

    Diese Definition ist dann verständlicher und die bessere wenn man die anderen lookarounds (positive/negative lookbehind/ahead) im Gesamten betrachtet.


    Denn das negative lookahead ((?!...)) lässt sich eigentlich nur so erklären dass das was vor dem lookbehind kommt gematcht wird, wenn das im lookahead eben gerade nicht folgt.

    Die Catastrophic Backtracking tauchen immer dann auf wenn in sich verschachtelte Konstrukte mit variablen Quantifizierern existieren welche jeweils für sich die gleichen Inhalte matchen können. Das führt dann dazu, dass der alle möglichen Kombinationen zwischen den beiden Quantifizierern durchgeht wenn kein Match existiert. Also eine Art Kreuzprodukt und das führt dann dazu dass das sich ziemlich fix hochschaukelt.

    Im Test funktioniert es, aber das heißt ja nicht unbedingt, dass es immer so funktioniert. Deshalb die Frage: Ist das so richtig, oder hat das noch andere Auswirkungen?

    Ne das passt super. Das (positive) Lookbehind (das (?=...) wirkt im Grunde so: behandele den Teil ganz normal aber lasse ihn nicht Teil des Matches werden. Daher kannst du (wie du es ja gemacht hast) damit die Leerzeichen Teil des Matches werden lassen oder eben nicht.

    Ja das ist bisschen doof.
    Wenn man die named capture group außerhalb des eigentlichen Matches definiert, dann wird daraus anscheinend implizit selbst ein Match der aber gleich wieder geleert wird.

    Ich hab die Logik dahinter noch nicht wirklich begriffen aber ich weiß zumindest wie man damit umgeht.

    Der Trick ist in dem Fall das DEFINE mit in die Capture-Group zu ziehen

    Somit braucht man bloß das Pattern ein bisschen umzustellen:


    >>ausgeschriebenes Pattern<<


    In Kurzform für dein Skript sähe das Pattern dann so aus und sollte dann die leeren Matches beseitigen:

    Code
    (?mi)^\h*Func\h+((?(DEFINE)(?<brackets>\((?|''(?>[^'']+|'''')*''|"(?>[^"]+|"")*"|[^\(\)\r\n"'']*|(?&brackets))*\)))\w+\h*(?&brackets)(?=\h*\R\h*EndFunc))


    Alternativ hättest du auch dein StringRegExp mit $STR_REGEXPARRAYGLOBALFULLMATCH aufrufen können und dir in der Schleife nur die zweite Gruppe von jedem Match auswählen können (also in der Schleife dann mit $aFuncs[$i][2] aufrufen).

    Ich gehe davon aus du siebst vorher immer noch Kommentare und Multiline-Commands (die Konstrukte mit _) aus?
    Sonst müsste man die noch mit extra behandeln.

    Matche: "Func" + FuncName + ausbalancierte Klammern mit allem dazwischen + nichts außer Space bis Zeilenende + "EndFunc" in der nächsten Zeile

    AutoIt
    #include <Array.au3>
    $sString = ClipGet()
    $sPattern = '(?mi)(?(DEFINE)(?<brackets>\((?:''(?>[^'']+|'''')*''|"(?>[^"]+|"")*"|[^\(\)\r\n"'']*|(?&brackets))*\)))^\h*(Func\h+\w+\h*(?&brackets)(?=\h*\R\h*EndFunc))'
    For $aMatch in StringRegExp($sString, $sPattern, 4)
    _ArrayDisplay($aMatch)
    Next


    Das Pattern in dieser Form zu betrachten ist nicht gesund - daher hier mal auseinanderklamüsert:

    >>Pattern für Funktionsheader<<

    Naja man könnte damit Funktionsdefinitionen (Funcname + alle Parameter) matchen, wenn man es so schreibt:

    Code
     (?ix)Func\h+\w+\h*(?<brackets> \( (?: '(?>[^']+|'')*' | "(?>[^"]+|"")*" | [^\(\)]*? | (?&brackets) )* \) )

    AutoIt kann ich gerade nicht testen da ich grad von Linux schreiben.

    Leider werden mit erfolgreichem Abfangen von mehrfachen ")" andere Fehler durchgelassen. :( Aber: Dein Tipp hat funktioniert! :)

    Damit hat sich meine Anfrage erledigt. Durch das Abfangen des genannten Fehlers werden andere Fehler durchgelassen, die zahlreicher sind und schwerer wiegen.


    Ich danke dir für die Hilfe beim Pattern und vorallem für den ausschlaggebenden Hinweis auf "Querschläger".

    Nanana noch nicht gleich die Flinte ins Korn werfen.

    Man kann doch auf balanzierte Klammern prüfen und dabei die innerhalb von Strings ignorieren:


    >>Beispiel<<

    Meine Frage ist, ob man das nicht auch eleganter (ressourcenschonender) lösen kann.

    Anstatt immer in einem bestimmten Intervall abzufragen ob so ein Fenster existiert wäre es eleganter sich von Windows benachrichtigen zu lassen wenn z.B. das Fenster im Vordergrund wechselt oder ein neues erstellt wird.

    Dann liegt die Auslastung bei nahezu 0%:


    Müssten die #region-#endregion nicht auch sowieso durch das Pattern "Alle Zeilen die nicht mit Func oder EndFunc angfangen" entfernt werden?

    Also wenn ja - warum dann eine Extra-Behandlung hierfür?


    Zum Thema mehrfachen Leerraum entfernen: Es muss nicht immer RegEx sein..: StringStripWS(..., 4)

    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: