Seite 1 von 1
Lange Zeile nach x Zeichen umbrechen
Verfasst: Mittwoch 24. September 2014, 13:00
von sfx2k
Hallo,
ich habe zwei Dateien mit jeweils nur einer Zeile Inhalt. Diese Zeile ist sehr lang und beinhaltet keine Leerzeichen.
Die Dateien unterscheiden sich in einigen Bytes.
Da mein Diff-Programm zeilenbasiert arbeitet, möchte ich gerne die Zeile nach jeweils x Zeichen umbrechen, um so im Viewer den Unterschied besser sehen zu können.
Ich habe das jetzt folgendermaßen gelöst, weiß aber nicht, ob das die optimale Lösung ist und würde Euch bitten, mal einen Blick darauf zu werfen.
Code: Alles auswählen
def crlf(src, target, count):
with open(src) as src_file:
new = ''
for line in src_file:
counter = 0
for char in line:
new += char
counter += 1
if counter % count == 0:
new += '\n'
with open(target, 'w') as target_file:
target_file.write(new)
Besten Dank.
Re: Lange Zeile nach x Zeichen umbrechen
Verfasst: Mittwoch 24. September 2014, 13:02
von Hyperion
Du könntest einfach das ``
textwrap``-Modul nutzen

Re: Lange Zeile nach x Zeichen umbrechen
Verfasst: Mittwoch 24. September 2014, 13:06
von BlackJack
Ich werde dann auch gleich noch mal einen Hinweis auf das `difflib`-Modul aus der Standardbibliothek los.

Re: Lange Zeile nach x Zeichen umbrechen
Verfasst: Mittwoch 24. September 2014, 13:39
von sfx2k
Vielen Dank für Eure Antworten
Hyperion hat geschrieben:Du könntest einfach das ``
textwrap``-Modul nutzen

Interessantes Modul

Allerdings braucht die Wrap-Routine für die Anzeige meines umgebrochenen Strings auf der Console 25 Sekunden, während meine Routine 4 Sekunden benötigt
Hast Du eine Idee, wie das sein kann? (Stringlänge 700000 Byte)
BlackJack hat geschrieben:Ich werde dann auch gleich noch mal einen Hinweis auf das `difflib`-Modul aus der Standardbibliothek los.

Ok, das schaue ich mir später mal an

Re: Lange Zeile nach x Zeichen umbrechen
Verfasst: Mittwoch 24. September 2014, 15:16
von BlackJack
@sfx2k: Das `textwrap`-Modul kann mehr und macht eigentlich ja auch ein bisschen etwas anderes als Du da brauchst. Das ist der Sonderfall den man in den Eingabedaten eigentlich nicht haben möchte, weil die ”Lösung” so hässlich ist Worte mittendrin einfach umzubrechen.
Allerdings ist Deine Lösung auch nicht wirklich gut weil da wenn's blöd läuft so an die 228 GiB an Daten im Arbeitsspeicher herumkopiert werden und Du wahrscheinlich einfach nur Glück hast, dass dieser Sonderfall in CPython in der Regel optimiert abläuft. Verlassen darf man sich da aber nicht drauf. Zeichenketten sind unveränderlich. Auch ein ``+=`` erzeugt eine neue Zeichenkette mit der Länge der alten beiden und die werden dann in diesen Speicherbereich kopiert. Wenn man das also in einer Schleife macht, in der diese Zeichenkette immer länger und länger wird, werden immer mehr und mehr Daten in jedem Durchlauf kopiert. Da Du das Zeichenweise machst, im ersten Durchlauf 1 Zeichen, im zweiten 2, im dritten 3, und im 700tausendsten 700.000, und da sind noch nicht mal die '\n' mitgezählt. Gesamt macht dass dann also mindestens die Summe von 1 bis 700.000:
Was Dich hier rettet ist das CPython bei Zeichenketten auf die es nur eine Referenz gibt beim ``+=`` schummelt und die Zeichenkette doch veränderbar macht. Sieht ja ausser dem einzigen Besitzer der Referenz niemand, und der bekommt das erwartete Ergebnis. Das geht so aber nur bei einer Speicherverwaltung die auf Referenzzähler setzt. Bei alternativen Python-Implementierungen wie IronPython oder Jython, die den jeweiligen Garbage Collector von .NET bzw. der JVM verwenden, geht das nicht, und auch bei CPython ist nicht garantiert das die Speicherverwaltung nicht irgendwann einmal geändert wird.
Es sieht auch recht kompliziert aus. Ich würde einfach die Eingabedatei in Blöcken zu x Bytes laden und dann jeweils mit einem '\n' in die Zieldatei schreiben.
Re: Lange Zeile nach x Zeichen umbrechen
Verfasst: Mittwoch 24. September 2014, 15:38
von sfx2k
BlackJack hat geschrieben:@sfx2k: Das `textwrap`-Modul kann mehr und macht eigentlich ja auch ein bisschen etwas anderes als Du da brauchst. Das ist der Sonderfall den man in den Eingabedaten eigentlich nicht haben möchte, weil die ”Lösung” so hässlich ist Worte mittendrin einfach umzubrechen.
Ja, sicher ein Sonderfall; in der Regel möchte man schon logisch umbrechen.
Das dachte ich mir auch, dass das Textwrap-Modul dafür nicht geschaffen worden ist
BlackJack hat geschrieben:
Allerdings ist Deine Lösung auch nicht wirklich gut
Daher fragte ich nach einer guten Lösung
BlackJack hat geschrieben:
weil da wenn's blöd läuft so an die 228 GiB an Daten im Arbeitsspeicher herumkopiert werden und [...]
Danke für diese ausführliche Erläuterung!
BlackJack hat geschrieben:
Ich würde einfach die Eingabedatei in Blöcken zu x Bytes laden und dann jeweils mit einem '\n' in die Zieldatei schreiben.
Hört sich gut an; vielen Dank
Habe es jetzt mal so umgesetzt:
Code: Alles auswählen
def crlf(src, target, count):
with open(src) as src_file:
with open(target, 'w') as target_file:
while True:
temp = src_file.read(10)
if not temp:
break
target_file.write(temp + '\n')
Re: Lange Zeile nach x Zeichen umbrechen
Verfasst: Mittwoch 24. September 2014, 16:14
von BlackJack
@sfx2k: Der Funktionsname ist sehr kryptisch und auch nur unter Windows richtig. Und anstelle der 10 sollte wohl ``count`` stehen.
Ungetestete Alternative:
Code: Alles auswählen
from functools import partial
def insert_newlines(source_filename, target_filename, count):
with open(source_filename) as source_file:
with open(target_filename, 'w') as target_file:
target_file.writelines(
block + '\n'
for block in iter(partial(source_file.read, count), '')
)
Oder falls Dir das zu verschachtelt ist mit einem zusätzlichen benannten Zwischenergebnis:
Code: Alles auswählen
def insert_newlines(source_filename, target_filename, count):
with open(source_filename) as source_file:
with open(target_filename, 'w') as target_file:
blocks = iter(partial(source_file.read, count), '')
target_file.writelines(block + '\n' for block in blocks)
Re: Lange Zeile nach x Zeichen umbrechen
Verfasst: Mittwoch 24. September 2014, 18:10
von sfx2k
BlackJack hat geschrieben:@sfx2k: Der Funktionsname ist sehr kryptisch und auch nur unter Windows richtig.
Ja, ich benutze es ja auch nur unter Windows

Aber hast recht; bei einer Sprache, die unter mehreren Systemen läuft, sollte man das berücksichtigen.
Ich tue mich nur immer so schwer, geeignete Bezeichner zu finden
BlackJack hat geschrieben:Und anstelle der 10 sollte wohl ``count`` stehen.

Upsi
BlackJack hat geschrieben:
Ungetestete Alternative:
Code: Alles auswählen
from functools import partial
def insert_newlines(source_filename, target_filename, count):
with open(source_filename) as source_file:
with open(target_filename, 'w') as target_file:
blocks = iter(partial(source_file.read, count), '')
target_file.writelines(block + '\n' for block in blocks)
Das sieht doch mal schick aus

Danke!
Re: Lange Zeile nach x Zeichen umbrechen
Verfasst: Mittwoch 24. September 2014, 19:58
von sfx2k
BlackJack hat geschrieben:
Code: Alles auswählen
def insert_newlines(source_filename, target_filename, count):
with open(source_filename) as source_file:
with open(target_filename, 'w') as target_file:
blocks = iter(partial(source_file.read, count), '')
target_file.writelines(block + '\n' for block in blocks)
Mein lieber Herr Gesangsverein.
Ich habe diese Routine jetzt mal verinnerlicht - da wäre ich nie so drauf gekommen (Partial)

Re: Lange Zeile nach x Zeichen umbrechen
Verfasst: Mittwoch 24. September 2014, 21:05
von cofi
sfx2k hat geschrieben:Ich habe diese Routine jetzt mal verinnerlicht - da wäre ich nie so drauf gekommen (Partial)

Das ist doch aber nicht mehr als ein Funktionsobjekt (wie es auch `lambda` erstellt), `iter` und sein 2. Parameter sind da doch interessanter
