Text aus Datei kopieren, ändern, einfügen...

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
polyworks
User
Beiträge: 14
Registriert: Montag 7. April 2014, 08:24

Hallo Leute!

Ich arbeite gerade an folgendem Programm: Ich möchte in einer txt-Datei einen bestimmten Bereich aufsuchen (Beispiel: Zeile 10-70), also anfangzeile= 10 und endezeile = 70; diese Zeilen einer Variable zuweisen, dann in diesem Bereich einen bestimmten Text suchen und mit einer fortlaufenden Zahl ersetzen ("__1" mit "__2" und "__0" mit "__1"). Den neuen Text möchte ich dann in der Zeile 71 einfügen bzw. anhängen, also den Text dahinter und davor NICHT löschen... Das Ganze soll dann in einer Schleife 100 mal durchgeführt werden, bis ich "__99" mit "__100" ersetze. Die Datei sieht wie folgt aus:

"
BEGIN OPERATION
TYPE = Backward 2D
VAR_IN = A__0
VAR_IN = Abstand
VAR_OUT = A__1
END OPERATION

BEGIN OPERATION
TYPE = Fit Vector
VAR_IN = A__0
CONST_IN = 0
VAR_IN = A__1
CONST_IN = 0
VAR_OUT = Vec__1
END OPERATION

BEGIN OPERATION
TYPE = Point From Vector
CHOICE_IN = Second Endpoint
VAR_IN = Vec__1
VAR_OUT = ende_vec__1
END OPERATION

BEGIN OPERATION
TYPE = Point From Vector
CHOICE_IN = First Endpoint
VAR_IN = Vec__1
VAR_OUT = drehpunkt__1
END OPERATION

BEGIN OPERATION
TYPE = Rotate Vector
VAR_IN = Vec__1
VAR_IN = drehpunkt__1
CONST_IN = 270
VAR_OUT = NV__1
END OPERATION

BEGIN OPERATION
TYPE = Point From Vector
CHOICE_IN = Second Endpoint
VAR_IN = NV__1
VAR_OUT = obenP__1
END OPERATION

BEGIN OPERATION
TYPE = Backward 2D
VAR_IN = A__1
VAR_IN = Abstand
VAR_OUT = A__2
END OPERATION
"

Das "A__2" am Ende ist dann der Anfang vom neuen Block, würde also so weiter gehen:

"BEGIN OPERATION
TYPE = Backward 2D
VAR_IN = A__2
VAR_IN = Abstand
VAR_OUT = A__3
END OPERATION

BEGIN OPERATION
TYPE = Fit Vector
VAR_IN = A__2
CONST_IN = 0
VAR_IN = A__3
CONST_IN = 0
VAR_OUT = Vec__3
END OPERATION
.
.
.
"

Bis jetzt geht mein Quellcode so weit, dass ich innerhalb der Datei finde und einer liste zuweise:

Code: Alles auswählen

with open (pfad) as rfile:
            lines =rfile.readlines()[anfangzeile:endezeile]
Danach ersetze ich alles richtig und würde nun jeden einzelnen Index der Liste zeilenweise ab der Zeile "endezeile+1", also 71, einfügen. Bis jetzt weiß ich noch nicht, wie ich die einzelnen Werte der Liste zeilenweise da eingefügt bekomm, aber das würde ich schon irgendwie hinbekommen.

Ich frage mich nur: gibt es da vielleicht einen eleganteren Weg, also z.B. mit einem einzelnen String zu arbeiten, in welchen ich den ganzen Text einfüge, bearbeite und in die Datei wieder einbinde?
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Typische BlackJack-Itertools-Aufgabe. Ich bin gespannt... ^^
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Generell solltest Du Dich davon lösen, "Dateien zu bearbeiten". Das geht idR. nicht oder ist extrem kompliziert. Einfacher ist es, den *Inhalt* einer Datei zu ändern und den gesamten Inhalt in eine *neue* Datei zu schreiben. Natürlich kann man auch die alte überschreiben, der Inhalt ist dann aber komplett neu.

Ich würde es wohl so angehen, dass ich die Datei einlese und während des Einlesens prüfe, ob ich den Index der zu analysierenden Zeile erreicht habe. Wenn nein, übergebe ich die gerade gelesene Zeile einfach an die Zieldatenstruktur. Wenn ja, parse ich bis zum Erreichen der Endzeile die jeweiligen Zeilen und suche nach den zu ändernden Stellen. Diese Zeilen oder Stellen merke ich mir in einer separaten Struktur, um sie später einzufügen. Jede Zeile kommt dann wieder in die Zielstruktur.

Erreiche ich die Endzeile + 1, so muss ich alle generierten Zeilen auf einmal an die Zielstruktur anhängen oder ich generiere mir diese genau jetzt.

Danach trifft keine Bedingung mehr zu und ich kann jede Zeile - wie zu Beginn - direkt in die Zielstruktur überführen.

Ganz am Schluss muss ich diese nur noch in eine Datei schreiben :-)

Als Struktur sollte eine Liste ideal sein.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Nach mehrmaligen Durchlesens des Themas würde mich doch mal interessieren, inwiefern diese Blöcke identisch / statisch sind. Evtl. kann man das über Templates viel einfacher und eleganter lösen, bevor man über wildes Parsing nachdenkt.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
MagBen
User
Beiträge: 799
Registriert: Freitag 6. Juni 2014, 05:56
Wohnort: Bremen
Kontaktdaten:

Wie schon gesagt, erstmal alle Daten in den Speicher holen, dort bearbeiten und dann wieder speichern.

Das Bearbeiten kannst Du Dir leichter machen, wenn Du die Gruppenstruktur der Daten im Text auch im Speicher hast, z.B. mit einer Liste von Listen:

Code: Alles auswählen

groups = [group.split("\n") for group in "".join(open(pfad).readlines()).split("\n\n")]
print( groups[1][3]) # 2.Gruppe, 4.Zeile
Wenn das "\n\n" als Gruppentrenner zu unsicher ist (wenn die Leerzeile, z.B. nicht leer ist, sondern Leerzeichen enthält), dann kannst Du auch "END OPERATION" als Gruppentrenner nehmen.
a fool with a tool is still a fool, www.magben.de, YouTube
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@MagBen: »"".join(open(pfad).readlines())« ist die leicht komplizierte Umschreibung für »open(pfad).read()«. Dateien sollten auch wieder geschlossen werden, was bei Deinem Konstrukt aber so nicht möglich ist.

Code: Alles auswählen

with open(path) as lines:
    groups = list(iter(lambda: list(itertools.takewhile(lambda line:line.strip(), lines)), []))
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Hier eine (nicht komplett getestete) Variante, welche die Ersetzungen vorberechnet und die Daten zeilenweise in den Speicher holt:

Code: Alles auswählen

REPLACEMENTS = dict(
    ('{}\n'.format(i), '{}\n'.format(i + 1)) for i in range(100)
)

def modify_lines(lines):
    for line in lines:
        parts = line.split('__')
        replacement = REPLACEMENTS.get(parts[-1])
        if replacement is not None:
            yield '{}__{}'.format(parts[0], replacement)
        else:
            yield line


def main():
    with open('dein_infile') as infile:
        with open('dein_outfile') as outfile:
            for line in modify_lines(infile):
                outfile.write(line)
Die Sache mit dem Dateiausschnitt (von Zeile X bis Zeile Y) habe ich nicht so ganz verstanden und daher auch weggelassen.
polyworks
User
Beiträge: 14
Registriert: Montag 7. April 2014, 08:24

Danke für die zahlreichen Antworten, bringt mich auf jeden Fall weiter!

@Hyperion: Die Blöcke sind insofern identisch, als dass es ein "BEGIN OPERATION" und ein "END OPERATION" gibt, der Text und die Menge an Zeilen dazwischen kann / soll variabel sein.
Antworten