Anfänger: file open write sort close

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.
Schnäik
User
Beiträge: 10
Registriert: Freitag 8. Februar 2008, 17:27

Hi,

versuche mich gerade an Python und komme nicht weiter...

Ich habe ein File:

3 text...
5 text...
6 text...
6 text...
8 text...

In dieses File muss ich z.B. folgende Zeilen einfügen:

2 text...
7 text...

Hinterher soll es so aussehen:

2 text...
3 text...
5 text...
6 text...
6 text...
7 text...
8 text...

Direkt an der richtigen Stelle einfügen muss zum Glück nicht sein da jede Zeile mit einer Zahl beginnt. Also einfach mit file.write() einfügen und anschließend sortieren.

Ich schaffe das aber nicht in einem Arbeitsgang?! Die mir bekannten open Attribute lassen das scheinbar nicht zu - muss aber doch irgendwie gehen. Der aktuelle Stand sieht so aus:

open(file, 'a+') - neue Zeilen einfügen
file.close()
open(file, 'r') - alle Zeilen in Liste einlesen
file.close()
open(file, 'w') - alles sortiert neu schreiben
file.close()

Das kann es doch irgendwie nicht sein? Analog muss es doch auch in einem Rutsch möglich sein in einem File Strings zu ersetzen - ich kann aber über die Suche nichts finden was mich weiter bringt.

Für jeden Tipp dankbar!
Benutzeravatar
Craven
User
Beiträge: 223
Registriert: Dienstag 24. Januar 2006, 13:37

Hi und Willkommen im Forum.

Da die Einträge in der Datei anscheinend nur durch Zeilenumbrüche getrennt sind, könntest Du theoretisch die ganze Datei einlesen (wenn es nicht allzuviel ist, geht das schon), nach "\n" splitten und Du erhältst eine Liste mit allen Zeilen. Dann musst du, wie gesagt, die anderen Zeilen nur noch an die Liste anhängen, sortieren und wieder in die Datei schreiben. Aber ob sich das lohnt bzw. einfacher geht, ist die Frage.

Gruß, Craven

Edit: Ich sehe gerade, dass ich genau das geschrieben habe, was du schon vermutet hast. ;) Ich sollte genauer lesen, in Zukunft.

Edit 2: Ich habe keine Ahnung, wie das geht, was du meinst. Mein Ansatz wäre eben das, was ich geschrieben habe.
Zuletzt geändert von Craven am Freitag 8. Februar 2008, 18:21, insgesamt 1-mal geändert.
[code]q = 'q = %s; print q %% repr(q)'; print q % repr(q) [/code]
Gnushi
User
Beiträge: 77
Registriert: Dienstag 12. Dezember 2006, 09:49

Hi!
Schnäik hat geschrieben:Für jeden Tipp dankbar!
Falls das ein Realwelt-Problem ist, dann hilft die Shell weiter:

cat neue_zeilen.text >> datei.text
sort datei.text > datei_tmp.text
mv datei_tmp.text datei.text

(geht auch noch kompakter... ich weiss)

Gnushi
noise
User
Beiträge: 62
Registriert: Donnerstag 7. Februar 2008, 00:15

Code: Alles auswählen

f = open("test.txt", "r")
result = sorted(list(f) + ["2 text...", "7 text..."])
f.close()
`result` enthält dann das von dir gewünschte Ergebnis.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Nee, das wird nichts:

Code: Alles auswählen

>>> sorted(["2 Test", "10 Test"])
['10 Test', '2 Test']
noise
User
Beiträge: 62
Registriert: Donnerstag 7. Februar 2008, 00:15

Ja, das er cmp/key, seinen wünschen entsprechende definieren muss ist klar ;) Aber das war ja nicht die frage.

@OP:
http://docs.python.org/lib/typesseq-mut ... eq-mutable
(7), (8), (9), (10)

http://docs.python.org/lib/built-in-funcs.html#l2h-68


EDIT:
EyDu, es wird übrigens char für char verglichen und das Ergebnis korreliert bei bytestrings mit dem Hexadezimal code der chars der ASCII-Table. Das hätte ich vielleicht doch erwähnen müssen.

Die default Implementierung nutzt ``>`` (oder ``<``, muss mal im C source gucken) zum vergleich, dass folgende logisches Ergebnis liefert:

Code: Alles auswählen

>>> print "2 text..." > "10 text..."
True
>>> 
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Falls die Erläuterung an mich gerichtet sein sollte: mir brauchst du nicht zu erzählen, ich hab' das Beispiel schon auf dieses Problem hin konstruiert.

Hattest du mit deinem Satz vor Buzzword-Bingo zu spielen? Man kommt nämlich bei der Erläuterung auch gut ohne die Begriffe Bytestring, ASCII und Hexadezimal aus.

BTW: XML, UML und RPC ;-)
noise
User
Beiträge: 62
Registriert: Donnerstag 7. Februar 2008, 00:15

@Schnäik:
Hi, falls alle deine Zeilen mit einer Zahl anfangen und das die primäre Ordnung angibt und der Rest die sekundäre, da dürfte diese Lösung klappen. Es wird aber hier nicht auf Fehler überprüfte.

Code: Alles auswählen

import re
def sorter(v1, v2):
    def normalize(v):
        return re.sub(r"^(\d+)(.+)$",
                      lambda x: (int(x.groups()[0]), x.groups()[1]),
                      v.strip())
    return cmp(normalize(v1), normalize(v2))

f = open("test.txt", "r")
result = sorted(list(f) + ["2 a...\n", "10 text...\n",
                               "7 text...\n"], cmp=sorter)
f.close()

print result

Code: Alles auswählen

['2 a...\n',
 '3 text...\n',
 '5 text...\n',
 '6 text...\n',
 '6 text...\n',
 '7 text...\n',
 '8 text...',
 '10 text...\n']
EyDu hat geschrieben: Hattest du mit deinem Satz vor Buzzword-Bingo zu spielen?
Man kommt nämlich bei der Erläuterung auch gut ohne die Begriffe Bytestring, ASCII und Hexadezimal aus.
Ich wusste gar nicht das Bytestrings, ASCII und Hexadezimal Buzzwords sind. Und nein, man kommt ohne diese Begriffe nicht aus um das adäquat zu erklären. Schließlich kann sich darunter jeder was vorstellen. Schließlich belegt jedes char eine bestimmte Position in der ASCII Table die sich Hexadezimal ausdrücken lässt. Bytestring deshalb, weil wir hier keine Unicode-Strings übergeben haben (Bei Unicode-Strings kann man schlecht mit der ASCII Tabelle argumentieren, deshalb habe ich explizit Bytestring erwähnt).

Naja, wie dem auch sei, im Gegensatz zu dir habe ich ein Lösung gepostet, anstatt Läute anzufahren.

BTW: http://de.wikipedia.org/wiki/Troll_%28Netzkultur%29
Ja ist mal wider Freitag EyDu, heisse dicht?

EDIT: Code korrigiert und typos.
EDIT 2: argh, ``*`` im regexe durch ``+`` ersetzt. Danke @Gnushi.
Zuletzt geändert von noise am Freitag 8. Februar 2008, 19:51, insgesamt 1-mal geändert.
Gnushi
User
Beiträge: 77
Registriert: Dienstag 12. Dezember 2006, 09:49

Hi!

Meine Lösung ist so ähnlich, ebenfalls mit re und ohne Berücksichtigung von Fehlern:

Code: Alles auswählen

import re

def vergleich(a, b):
    expression = r'(\d+)'
    m1 = re.match(expression, a)
    av = int(m1.group(1))
    m2 = re.match(expression, b)
    bv = int(m2.group(1))
    if av > bv:
        return 1
    elif av < bv:
        return -1
    else:
        return 0


l = ['1 test', '2 test', '2 test', '10 test', '20 test', '4 test']
l.sort(vergleich)
print l
Gruß

Gnushi
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hallo Schnäik!

Willkommen im Python-Forum!
Schnäik hat geschrieben:Hinterher soll es so aussehen:
2 text...
3 text...
5 text...
6 text...
6 text...
7 text...
8 text...
Also zuerst habe ich ein wenig Lesestoff für dich. http://www.python-forum.de/topic-6157.html

Und was das gleichzeitige Lesen und Bearbeiten einer Textdatei betrifft -- mache es erst dann, wenn du genau weißt was du tust. Es ist nämlich so, dass du nicht einfach in der Mitte einer Datei etwas hinzufügen kannst. Du kannst etwas austauschen, aber nur so lange du damit die Größe der Datei nicht änderst.

Deshalb ist es eine gute Idee, wenn du zuerst die Textdatei nur zum Lesen öffnest, komplett in eine Liste einliest und dann wieder schließt. Danach kannst du die Daten zur Liste hinzufügen, sortieren und in ein zum Schreiben geöffnetes Datei-Objekt schreiben.
So lange du es nicht mir Dateien zu tun hast, die größer sind als dein Arbeitsspeicher, bist du damit auf der sicheren Seite. Handelt es sich allerdings um rießige Dateien, dann muss man anders vorgehen.

Die einfache Variante könnte z.B. so aussehen:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

# Alles in eine Liste einlesen und die "Zahl" in eine Zahl umwandeln (zum Sortieren)
datalist = []
inputfile = file("hallo.txt", "rU")
for line in inputfile:
    if line:
        linenumber = int(line.split(" ")[0])
        datalist.append([linenumber, line])
inputfile.close()

# Daten hinzufügen (Es ist wichig, dass im ersten Feld der Liste eine Zahl
# und kein Text steht. So kann besser sortiert werden.
datalist.append([2, "2 text...\n"])
datalist.append([7, "7 text...\n"])

# sortieren
datalist.sort()

# Speichern
outputfile = file("hallo2.txt", "w")
for linenumber, line in datalist:
    outputfile.write(line)
outputfile.close()
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Ich bin mir sicher, dass du mit den Begriffen zurecht kommst, einige andere und ich auch, aber dieser Satz ist einfach unnötig kompliziert.

Code: Alles auswählen

l = ["1 Test", "10 Test", "2 Test"]
l.sort(key=lambda x: int(x.split()[0]))
Gnushi
User
Beiträge: 77
Registriert: Dienstag 12. Dezember 2006, 09:49

Hi!
EyDu hat geschrieben:

Code: Alles auswählen

l = ["1 Test", "10 Test", "2 Test"]
l.sort(key=lambda x: int(x.split()[0]))
*heul!*

Sowas ist genau der Grund, warum ich Python so mag: Es gibt oft eine sehr elegante und schöne Lösung für eine konkrete Klasse von Problemen.

Gruß

Gnushi
noise
User
Beiträge: 62
Registriert: Donnerstag 7. Februar 2008, 00:15

EyDu hat geschrieben:

Code: Alles auswählen

l = ["1 Test", "10 Test", "2 Test"]
l.sort(key=lambda x: int(x.split()[0]))
Ich bin mir ziemlich sicher das er nicht nur nach den zahlen sortieren will, sondern auch nach dem Rest danach. Auserdem ist das ``split()`` recht gefährlich, da man es eventuell auch mit Zeilen der Form ``47Test`` zu tun haben kann. Aber das ist meinerseits Spekulation da wir immer noch nicht wissen wie genau sich die Zeilen zusammensetzten.


Zu den Begriffen: Es tut mir leid EyDu, aber ich wüsste nicht wie ich das ohne ein Roman zu schreiben ausdrücken sollte? Und ich hatte auch nicht vor ins Detail zu gehen in dem ich den aufbau der ASCII-Tabelle erkläre, was Hexadezimal, ... ist. Ich denke in einem Programmier Forum kann ich schon erwarten das die Leute wissen was ASCII, Unicode-String, Bytestring und Hexadezimal ist. Das sind Basics. Und wenn nicht hat man ja noch google, wiki, etc. oder kann gegebenenfalls nachhacken.

Aber mir HIER vorzuschreiben zu lassen was für Begriffe ich verwenden darf, wie ich meine Sätze - sei es orthographisch oder grammatisch, zu strukturieren habe und ungerechtfertigt Kommentare zu erdulden, muss nicht sein, oder? -- Wenn es wenigstens gerechtfertigt wäre würde ich ja meine klappe halten, aber so?

Ich bin bei deinem ersten post von eine sachlichen Kontext ausgegangen und habe darauf IMO auch sachlich geantwortet. Das du mir in deinem 2 post dann pampig rüberkommst ist IMO ungerechtfertigt, da ich dich in keinster weise Angegriffen habe, sondern deine **akkurate Beobachtung** nur Kommentiert habe.

Sei es drum, fürs nächste mal weiß ich wie ich mit deinen posts umzugehen habe.

EDIT:
Gnushi hat geschrieben: *heul!*

Sowas ist genau der Grund, warum ich Python so mag: Es gibt oft eine sehr elegante und schöne Lösung für eine konkrete Klasse von Problemen.
Kuck nochmal genauer hin, das macht was ganz anderes als deine und meine "Lösung".
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

noise hat geschrieben:Ich bin mir ziemlich sicher das er nicht nur nach den zahlen sortieren will, sondern auch nach dem Rest danach. [...] Aber das ist meinerseits Spekulation da wir immer noch nicht wissen wie genau sich die Zeilen zusammensetzten.
Nicht zu vergessen die aktuelle Mondphase, Stau auf der A7 und danach ob sein Hund gerade schläft ;-)
Gnushi
User
Beiträge: 77
Registriert: Dienstag 12. Dezember 2006, 09:49

Hi!
noise hat geschrieben: Kuck nochmal genauer hin, das macht was ganz anderes als deine und meine "Lösung".
Meine Lösung ist definitiv schlechter als seine. Er verwendet weniger Zeilen und ich sortiere ebenfalls nur nach der Nummer, weil ich bisher davon ausgehen kann, dass der restliche Text identisch ist.

Teste das mal mit

Code: Alles auswählen

l = ['2 atest', '2 ctest', '2 btest']
Gruß

GnuShi
Schnäik
User
Beiträge: 10
Registriert: Freitag 8. Februar 2008, 17:27

Wow, was seid Ihr denn hier für ein geiler Haufen?! Vielen Dank für die vielen schnellen Antworten!

Scheint als wäre der Ansatz gar nicht so verkehrt gewesen - mir kam nur das ständige File auf/ File zu etwas seltsam vor:

Code: Alles auswählen

datei  = 'test.txt'
file = open(datei, 'a+')
file.write('3 bla\n')
file.write('7 blubb\n')
file.close()

file = open(datei, 'r')
lines = file.readlines()
file.close()

file = open(datei, 'w')
file.writelines(sorted(lines))
file.close()
Gnushi hat geschrieben:Hi!
Falls das ein Realwelt-Problem ist, dann hilft die Shell weiter:
Danke - das Realwelt-Problem ist schon gelöst (Shell/Perl) aber ich dachte das wäre mal ein guter Einstieg in Python. Ist auch nur ein kleiner Teil des Ganzen...
noise hat geschrieben:

Code: Alles auswählen

f = open("test.txt", "r")
result = sorted(list(f) + ["2 text...", "7 text..."])
f.close()
`result` enthält dann das von dir gewünschte Ergebnis.
Das ist auch gut - bei mir läufts andersum. Die weiteren Ansätze hinsichtlich der Sortierung sind für mein aktuelles Problem oversized - die Zahlen zu Beginn einer Zeile haben in weiser Voraussicht alle die gleiche Länge bekommen - also mit führenden Nullen ;-) Der Rest danach würde nur bei gleicher Zahl relevant werden und spielt dann keine Rolle. Aber es ist nur eine Frage der Zeit bis was anderes kommt und deshalb habe ich mir die High-End Lösung auch mal gesichert :shock:
gerold hat geschrieben: Und was das gleichzeitige Lesen und Bearbeiten einer Textdatei betrifft -- mache es erst dann, wenn du genau weißt was du tust. Es ist nämlich so, dass du nicht einfach in der Mitte einer Datei etwas hinzufügen kannst. Du kannst etwas austauschen, aber nur so lange du damit die Größe der Datei nicht änderst.
Das ist mir im Grunde klar, das viele hin und her kam mir aber trotzdem seltsam vor. Hat das Schreiben via FOR Schleife Vorteile gegenüber file.writelines?

Als blutiger Anfänger habe ich hier und da noch das Gefühl dass ich mit Perl schneller ans Ziel komme. Aber bei der Rückendeckung hier beisse ich mich noch mal eine Weile durch. Seid selbst schuld, jetzt bin bestimmt bald mit der nächsten Frage wieder hier ;-)
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hallo Schnäik!
Schnäik hat geschrieben:

Code: Alles auswählen

file = open(datei, 'a+')
1.) Das "+" brauchst du nicht. Siehe: http://docs.python.org/lib/built-in-funcs.html#l2h-54
2.) ``file`` ist ein eingebauter Typ den du hier überschreibst
Schnäik hat geschrieben:Hat das Schreiben via FOR Schleife Vorteile gegenüber file.writelines?
Es hat dann Vorteile, wenn man mit jeder einzelnen Zeile etwas tun möchte. Das gilt für ``readlines()`` und für ``writelines()``. Aber in deinem Fall hat es keinen Vorteil.

Der große Vorteil der FOR Schleife kommt dann zum Tragen, wenn man sie mit ``read()`` vergleicht. ``read()`` liest die ganze Datei in den Speicher. Wenn man mit einer FOR Schleife über die Datei iteriert, dann wird die Datei zeilenweise in den Speicher geladen. Dieser wird etwas später wieder frei gegeben.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Schnäik
User
Beiträge: 10
Registriert: Freitag 8. Februar 2008, 17:27

gerold hat geschrieben:Hallo Schnäik!
Schnäik hat geschrieben:

Code: Alles auswählen

file = open(datei, 'a+')
1.) Das "+" brauchst du nicht. Siehe: http://docs.python.org/lib/built-in-funcs.html#l2h-54
2.) ``file`` ist ein eingebauter Typ den du hier überschreibst
Ups... ;-)

Danke Gerold für die Tipps!
noise
User
Beiträge: 62
Registriert: Donnerstag 7. Februar 2008, 00:15

EyDu hat geschrieben:Nicht zu vergessen die aktuelle Mondphase, Stau auf der A7 und danach ob sein Hund gerade schläft ;-)
Du hast mit dem Thema sortieren angefangen. Und wenn dann richtig, weil sonst ist es genauso wenig Wert wie meine ursprüngliche Lösung ;) Tja, besonders konsistent scheinst ja nicht zu sein.

Ein schönes *PLONK* und du hast dir den falschen Neuling hier im Forum ausgesucht für deine Spielchen ;)
Gnushi hat geschrieben:Er verwendet weniger Zeilen und ich sortiere ebenfalls nur nach der Nummer,
Okay, das hatte ich übersehen.
Schnäik hat geschrieben:Wow, was seid Ihr denn hier für ein geiler Haufen?!
:D
Schnäik hat geschrieben:Die weiteren Ansätze hinsichtlich der Sortierung sind für mein aktuelles Problem oversized - die Zahlen zu Beginn einer Zeile haben in weiser Voraussicht alle die gleiche Länge bekommen - also mit führenden Nullen ;-)
Das dürfte sicherlich EyDu interessieren :D
Schnäik hat geschrieben:Seid selbst schuld, jetzt bin bestimmt bald mit der nächsten Frage wieder hier ;-)
Über Fragen freuen wir uns :) Und ich sie zu beantworten, und EyDu meine Antworten auf unsachliche weise zu Kommentieren ;)
BlackJack

Zu den ganzen "Vergleichern" mit dem `cmp`-Argument von `list.sort()`: Das `key`-Argument ist in der Regel vorzuziehen, weil die übergebene Funktion nur einmal pro Element aufgerufen wird, während die `cmp`-Funktion für jeden Vergleich beim Sortieren aufgerufen wird.

@noise: Die Worte "ASCII" und "Hexadezimalcode" wären nicht nötig gewesen. Es wird nach den Werten der Bytes im Bytestring verglichen, reicht als Erklärung. In welchen Zahlsystemen man die Werte darstellen kann ist egal. Ausserdem könnte Deine Erklärung mit ASCII die Frage aufwerfen, was die Vergleichsoperationen wohl mit den Werten 128 bis 255 machen. :P

@Gnushi: In Deiner `vergleich()`-Funktion kannst Du das ``if``/``elif``/``else``-Gedöns durch ``return cmp(av, bv)`` ersetzen.
Antworten