Microsoft Word: Suche und ersetze Text in den Inhalten der VBA-Progammierung (gelöst)

  • Hallo Water,

    vielen Dank für Deine kritische Betrachtung.

    Tatsächlich kann ich auf FileOpen verzichten, da ich die Files nur auslese, aber nicht manipuliere.

    $col wird mit Funktionsaufruf von _read_file definiert.

    Beim ersten Funktionsaufruf von _read_file ist das Array von $aTags noch 1D,

    Beim zweiten Funktionsaufruf von _rad_file ist es 2D.

    $file_s und $file_r müssen so belegt sein, dass die Zeilen entsprechend korrespondieren.

    In jeder Zeile von $aTags steht dann in der ersten Spalte der Such-String und in der zweiten Spalte der entsprechende Ersetzen-String.
    Sonst würde der Aufruf von $aTags in Word_DocFindReplace auch nicht funktionieren.

    Buchstabe "W" hatte ich eigentlich schon herauseditiert - keine Ahnung, weshalb Du den noch sehen konntest.

    Der Code ist nur um sehr spezifische Datails gekürzt, dennoch voll funktionsfähig, so wie er da steht.

  • Ganz nebenbei:

    Dein Return in _read_file brauchst du nicht, da du die Funktion nicht mit Zuweisung aufrufst.

    Außerdem verhindert dies die Ausführung des File close.

    Zudem definierst du zwei Variablen LOCAL werden aber GLOBAL sein, da sie im globalen Kontext stehen

    Hier mal dein Skript abgeändert (Zeile 31 auskommentiert, da aktuell nicht verwendet in dem geposteten Code).

    Du müsstest es halt nochmal testen, da ich div. kleine Änderungen vorgenommen habe. Unteranderem:

    - Variablen in den richtigen Kontext verschoben (wenn sie Global gesetzt waren aber nur Lokal verwendet wurden)

    - Variablen deklaration an den Anfang der Funktion(en) gesetzt, anstatt mitten im Code

    - Variablen um Const ergänzt wenn diese nicht verändert werden (dürfen)

    - einzelne Variablennamen geändert um sie eindeutiger zu machen was sie beinhalten (z.B. $i in $iRow)

    - Das Array $aTags ByRef übergeben anstatt direkt auf die Globale Variable zuzugreifen.

    - Return aus der Funktion _read_file entfernt

    - Prüfung am Anfang des Skriptes ob Parameter übergeben wurden, sonst direkter Programmabbruch um Fehlermeldungen zu vermeiden

    - Bei den msgboxen den Wert 16 durch die Konstante ersetzt

    - Korrektur der Funktion _read_file auf die von water (s.u.)

    9 Mal editiert, zuletzt von Moombas (5. Juli 2023 um 11:21)

  • Tatsächlich kann ich auf FileOpen verzichten, da ich die Files nur auslese, aber nicht manipuliere.

    Das hat in Deinem Fall mit der Art der Manipulation nichts zu tun.

    Nehmen wir an, Du hast 1000 Datensätze in einer Datei, dann führt FileReadLine dazu, dass die folgende Schleife 1000 mal durchgeführt wird:

    • Datei öffnen
    • angegebene Zeile suchen
    • Zeile lesen
    • Datei schließen

    Mit FileOpen/FileClose/FileRead sieht das so aus:

    • Datei öffnen
    • 1000x Zeile lesen (ohne Angabe der Zeilennummer läuft ein Positionspointer mit der immer auf die nächste zu lesende Zeile zeigt)
    • Datei schließen

    Da Datei öffen, Datei schließen sowie die Suche zur nächsten zu lesenden Zeile sehr zeitaufwändig sind (bei Zeile suchen nimmt der Aufwand mit der Anzahl der Zeilen zu) ist das hier ein reines Performance-Problem.

    N.B. In Deinem Code rufst Du _FileCountLines 2x auf. Sinnvoller wäre, das Ergebnis von _FileCountLines in einer Variablen zu speichern und dann in der Schleife zu verwenden. Oder nach FileReadLine den Fehlercode abzuprüfen. Der sagt Dir dann, dass das Ende der Datei erreicht wurde.

    N.B. Magic Numbers (0 bei FileOpen etc.) sollten vermieden und durch die entspr. Konstanten ersetzt werden (siehe Code unten). Konstanten sind selbsterklärend und bei Kombinationen mehrerer Werte einfacher zu lesen.

    Lösch also FileOpen/FileClose komplett raus (langsame Variante) oder ersetze den bisherigen Code durch:

    Der Code könnte noch optimiert werden, wenn _FileCountLines durch $iRow ersetzt würde. Zu zählst zuerst alle Zeilen, nach der Befüllung des Arrays hast Du aber als Nebeneffekt (und ohne Performance-Verschlechterung) in $iRow die Anzahl der Zeilen stehen.

    Die Befüllung des Arrays ließe sich auch noch optimieren.

  • Moin!

    vielen Dank für die Erläuterungen und Codeanpassungen.

    Ihr habt den Code aber nicht getestet, oder? - da stecken noch drei kleine Fehler drin:

    in Zeile 24 muss die Variable $aTags als Array definiert sein, also Global $aTags [1]

    in Zeile 46 muss Next durch WEnd ersetzt werden.

    Außerdem habe ich festgestellt, dass das Array $aTags leer bleibt - muss noch prüfen, woran das liegt.

    Einmal editiert, zuletzt von MiX-MoX (5. Juli 2023 um 10:05)

  • Japp, habs korrigiert und noch eine andere Stelle (du erwartest ja ein 1-basiertes Array und kein 0-basiertes).

    Ein wirkliches Testen ohne samplefiles ist halt schwer.

    Teste bitte nochmal das komplette Skript von oben.

  • Hier mal die etwas korrigierte Version (mit deinen Test Dateien; ich habe die Anzeige des Word Dokuments mal auf False gesetzt (Zeile 50)):

    Ich gehe davon aus das der Dateiname (du suchst ja nach einem fixen Dateinamen) nur einmal zu finden ist (du speicherst mit einem festen Namen, der sich nicht auf Grund der gefundenen templates ändert), dann brauchst du die Schleife zum durchgehen der templates nicht, sondern kannst gleich auf den ersten Eintrag gehen.

    Zeile 13-18 musst du noch anpassen, ich habe es nur mal drinne gelassen (17&18) um zu Zeigen, was ich verwendet habe.

    Andernsfalls müsstest du so vorgehen (dann gehe ich davon aus das der Dateiname mehrfach in versch. Unterordnern existiert):

  • MiX-MoX Ich sag es dir ganz ehrlich: Du schaust hier regelmäßig rein und mein "Fix" scheint ja zu funktionieren, denn sonst wärst du sicherlich mit einer negativen Meldung um die Ecke gekommen aber dann nicht mal ein "Danke" und/oder Feedback da zu lassen finde ich nicht gut und wird dafür sorgen, das (zumindest mich betreffend) es sein kann, das dir nicht mehr geholfen wird.

  • Moombas

    sorry für mein langes schweigen. Hab Sommergrippe und warte noch auf Genesung bzw. einen klaren Kopf...

    Soweit ich das beim Überfliegen erkennen kann passt das soweit - zum Testen bin ich noch nicht gekommen.