Textabschnitt (Text Abschnitt) ersetzen (und dabei nicht jede Zeile einzeln)

  • Hallo,

    erstmal goßes Lob und ein herliches Dankeschön. :thumbup: Das Forum hier hat mir als Anfänger schon in schon bei vielen meiner Fragen eine Lösung ermöglicht.
    In einem Punkt komm ich jetzt aber nicht weiter und hoffe, daß mir hier eventuell jemand auf die Sprünge helfen kann.

    Die verschiedenen Möglichkeiten zum Ersetzten einzelner Zeilen habe ich soweit verstanden. Wie man aber einen Abschnitt aus ziel.txt mit einem Abschnitt aus quell.txt ersetzt, ohne daß das in unzählige code ausartet ist mir nicht klar. Komm hier auch mit der Autoit Hilfe einfach nicht weiter. ?(

    Ausgangslage:

    1) quell.txt mit den Zeilen 1-100
    2) ziel.txt mit den Zeilen 1-500

    Ergebnis soll sein:

    ziel.txt in der die Zeilen 301-400 mit den Zeilen 1-100 aus quell.txt ersetzt wurden.
    (In meinem konkreten Fall ist die Zeilenanzahl immer identisch.)

    Ich habe mir die benutzerdefinierten Funktion zu Array + Dateien angeschaut, finde aber keine einfache Lösung. Umgekehrt wäre es ja einfach mit _FileWriteFromArray da ich dort dort ja über optionalen Startindex und letzten Index eines Arrays die zu kopierenden Zeilen von quell.txt festlegen könnte.

    Ich bräuchte es aber ja quasi "umgekehrt". Wie mach ich das am besten? Beide *.txt in ein Array einlesen und dann?
    Oder ganz anders?

    Wäre für jede Hilfestellung dankbar.

    Grüße
    t002

    Einmal editiert, zuletzt von t002 (19. April 2010 um 18:13)

  • Sowas in der Art ?
    (Achtung! Ungetestet!)

    Spoiler anzeigen
    [autoit]

    Global $sDelim = @CRLF, $sRet, $aSource = StringSplit(FileRead("Quell.txt"),$sDelim,1), $aDest = StringSplit(FileRead("Ziel.txt"),$sDelim,1)
    If UBound($aDest) < 401 Or UBound($aSource) < 101 Then Exit MsgBox(16,"Fehler","Fehler beim einlesen der Dateien")
    For $i = 301 To 400
    $aDest[$i] = $aSource[$i-300]
    Next
    For $i = 1 To $aDest[0]
    $sRet &= $aDest[$i] & $sDelim
    Next
    FileDelete(@ScriptDir & "\Ziel_Neu.txt")
    FileWrite(@ScriptDir & "\Ziel_Neu.txt",StringTrimRight($sRet,StringLen($sDelim)))

    [/autoit]

    //EDIT: Syntaxfehler korrigiert ^^

  • im prinzip einfach beide fildes zur array lesen, dann mit dem index entsprechend ersetzen
    danach kannst du die komplette fertige array in eine file schreiben
    wenn du es nicht schaffst, kannst du ja in diesen spoiler gucken ;)

    Erst versuchen ;)
    [autoit]

    #include <Array.au3>
    #include <File.au3>
    Global $aQuellTxT, $aZielTxT, $aErgTxt, $iI = 0
    If _FileReadToArray(@ScriptDir & "\quell.txt", $aQuellTxT) Then ; Wenn Ergebnis True, dann...
    If _FileReadToArray(@ScriptDir & "\ziel.txt", $aZielTxT) Then
    For $i = 301 To 400
    $iI += 1
    $aZiel[$i] = $aQuell[$iI]
    Next
    EndIf
    EndIf
    _ArrayDisplay($aErgTxT, "Das Ergebnis:")

    [/autoit]

    Das sollte erfüllen, was du willst, bitte korregiere mich jemand, wenn ich es falsch gemacht habe ;) Eher unwarscheinlich ^^

    Edit1: SEuBo du warst schneller :(

  • @ SEuBo

    Vielen Dank! :) Ich versteh zwar nicht wirklich, was Du da mit Deinen beiden kleinen aber feinen for Schleifen veranstaltest, funktioniert aber super.

    @ black_skorpi

    Gleichfalls vielen Dank. Dein Lösungsvorschlag geht eher in eine Richtung, die ich mit meinem Wissensstand nachvollziehen könnte. Leider funktioniert es nicht. :(
    Ich krieg folgende Fehlermeldung: "Expected a "=" operator in assignment statement"

    Ich setz jetzt auf gelöst, interessieren würds mich schon, wie das mit UDFs funktionieren würde.
    Aber soweit ich das überblicken kann, wird zudem das "Ergebnis Array" ja gar nicht bestückt, oder? :huh: Kann es sein, dass Du in der Eile da einfach eine Zeile vergessen hast?

    Grüsse
    t002

  • Hallo,

    Erstmal das berichtige von skorpi

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>
    #include <File.au3>
    Global $aQuellTxT, $aZielTxT, $aErgTxt, $iI = 0
    If _FileReadToArray(@ScriptDir & "\quell.txt", $aQuellTxT) Then ; Wenn Ergebnis True, dann...
    If _FileReadToArray(@ScriptDir & "\ziel.txt", $aZielTxT) Then
    For $i = 301 To 400
    $iI += 1
    $aZielTxt[$i] = $aQuellTxT[$iI]
    Next
    EndIf
    EndIf
    _ArrayDisplay($aZielTxt, "Das Ergebnis:")
    _FileWriteFromArray(@ScriptDir & "\ziel_neu.txt",$aZielTxt,1)

    [/autoit]


    Also im Grunde verwenden ich und black_skorpi das selbe Script. Es sind nur kleine Unterschiede.
    Zum Beispiel schreibt er

    [autoit]

    _FileReadToArray(@ScriptDir & "\quell.txt", $aQuellTxT)

    [/autoit]


    Ich dagegen würde schreiben

    [autoit]

    $aQuellTxt = StringSplit(FileRead(@ScriptDir & "\quell.txt"),@CRLF,3))

    [/autoit]

    _FileReadToArray macht nämlich nichts anderes, als eine Datei komplett einzulesen (FileRead) und an den Zeilenumbrüchen zu teilen (StringSplit).
    Ich hab mir deswegen angewöhnt bei vielen Sachen auf UDF's zu verzichten, wenn man das ganze auch ohne Include in 1 Zeile verpacken kann.

    Kurz noch vorweg:
    Die For-Next Schleife sorgt dafür etwas beliebig oft zu wiederholen. Die Variable (i.d.R. $i) ist die sog. Laufvariable und enthält immer den aktuellen "Zähler" der Schleife.

    Die erste Schleife zählt von 301 bis 400, was den Zeilen in der Ziel.txt entspricht, die ersetzt werden sollen.
    Black Scorpi hat die Selbe schleife wie ich. Ausnahme: Ich rechne einfach $i-300 um die richtige Zeile in der Quell.txt zu erreichen.
    In dem Script von Scorpi wird eine extra Zählervariable $iI verwendet.

    Die zweite Schleife, schreibt den Array wieder in einen String. Das ist eigentlich nichts anderes als

    [autoit]

    _ArrayToString($aDest,@CRLF,1)

    [/autoit]

    Ganz am Ende wird eine evtl. vorhandene "Ziel_ersetzt.txt" gelöscht, und dann per FileWrite() in die Datei geschrieben.
    Das StringTrimRight sorgt dafür, dass der letzte Zeilenumbruch aus der For-Next Schleife wieder entfernt wird (sonst gibts ne leerzeile).
    Warum überhaupt die Datei löschen? So erspare ich mir eine weitere Zeile, als wenn ich mit FileOpen arbeiten würde. Sonst bräuchte man

    [autoit]

    $hFile = FileOpen(@ScriptDir & "\Ziel_Neu.txt",2) ; Schreibmodus öffnen. Vorherigen Inhalt löschen
    FileWrite($hFile,$sRet) ; Neuen Text schreiben
    FileClose($hFile) ; schließen

    [/autoit]


    Mit FileDelete braucht man nur

    [autoit]

    FileDelete(@ScriptDir & "\Ziel_Neu.txt")
    FileWrite(@ScriptDir & "\Ziel_Neu.txt,$sRet)

    [/autoit]


    Und zuguterletzt:
    So würde mein Script in UDF Form aussehen

    Spoiler anzeigen
    [autoit]

    #include <File.au3>
    Global $aSource, $aDest
    If Not _FileReadToArray(@ScriptDir & "\Quell.txt", $aSource) Then Exit MsgBox(16, "Fehler", "Fehler beim einlesen der Dateien")
    If Not _FileReadToArray(@ScriptDir & "\Ziel.txt", $aDest) Then Exit MsgBox(16, "Fehler", "Fehler beim einlesen der Dateien")
    For $i = 301 To 400
    $aDest[$i] = $aSource[$i - 300]
    Next
    _FileWriteFromArray(@ScriptDir & "\Ziel_Neu.txt", $aDest, 1)

    [/autoit]


    PS: Rein interessehalber: Klappt das hier?

    [autoit]

    FileDelete(@ScriptDir & "\Ziel_neu.txt")
    FileWrite(@ScriptDir & "\Ziel_neu.txt", StringRegExpReplace(FileRead(@ScriptDir & "\Ziel.txt"), "(?>.+\n\r?){300}((?>.+\n\r?){100})", StringRegExpReplace(FileRead(@ScriptDir & "\Quell.txt"), "(?>.+\n\r?){100}([\w\W]+)", "")))

    [/autoit]
  • Merci. :thumbup:

    Superausführliche und gute Erklärung des ganzen. Hab alles verstanden soweit und bin jetzt klüger als zuvor. ;)

    Obwohl mirs jetzt völlig klar erscheint, war mein grösstes Verständnisproblem eigentlich, dass das hier

    Code
    $aDest[$i] = $aSource[$i-300]

    ausreicht, um die Zeilen zu übernehmen. Irgendwie hatten sich da [$i] und [0] für den Index auf merkwürdige Weise in meinem Kopf verknotet.

    Zitat

    PS: Rein interessehalber: Klappt das hier?

    Nein, klappt leider nicht. Prozessorauslastung bei dauerhaften 50% und killen lässt sich das Script nur noch per Taskmanager.


    Also Danke nochmal + Grüße
    t002

  • Ich schalt mich mal dazu :D

    For schleifen versteht man(ich) am einfachsten wenn man sich die ersten Schritte durchdenkt, also in deinem Fall so:

    Schleife:

    [autoit]


    For $i = 301 To 400
    $aDest[$i] = $aSource[$i - 300]
    Next

    [/autoit]

    Die Schleife beginnt bei 301 zu zählen..
    Dann sieht der Code in der Schleife so aus:
    In das Element Nr 301 vom Array $aZielTxt wird das Element Nr 1 (301 - 300) des Arrays $aSource geschrieben
    Nächste Durchlauf:
    In das Element Nr 302 vom Array $aZielTxt wird das Element Nr 2 (302 - 300) des Arrays $sSource geschrieben
    Nächster Durchlauf:
    In das Element Nr 303 vom Array $aZielTxt wird das Element Nr 3 (303 - 300) des Arrays $sSource geschrieben
    usw..

    demnach überschreibt er alle Elemente des Arrays $aZielTxt im Bereich von 300 bis 400 mit den Elementen des Arrays $aSource im Bereich 1 bis 100..

  • Nein, klappt leider nicht. Prozessorauslastung bei dauerhaften 50% und killen lässt sich das Script nur noch per Taskmanager.

    Einfach weil ich es mir beweisen muss:

    [autoit]

    Local $aQuell = StringRegExp(FileRead(@ScriptDir & "\Quell.txt"), "\A(?>.+\n\r?){100}", 3), $1 = FileDelete(@ScriptDir & "\Ziel_neu.txt"), $2 = FileWrite(@ScriptDir & "\Ziel_neu.txt", StringRegExpReplace(FileRead(@ScriptDir & "\Ziel.txt"), "((?>.+\n\r?){300})((?>.+\n\r?){100})", "\1" & $aQuell[0]))

    [/autoit]

    Das Script ist sogar getestet und funktioniert :D ( Nein, das ist nicht kaputt - das ist eine Zeile ^^)