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

Freitag 8. Februar 2008, 17:58

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

Freitag 8. Februar 2008, 18:10

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

Freitag 8. Februar 2008, 18:17

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

Freitag 8. Februar 2008, 18:21

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: 4871
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Freitag 8. Februar 2008, 18:29

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

Freitag 8. Februar 2008, 18:42

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: 4871
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Freitag 8. Februar 2008, 18:59

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

Freitag 8. Februar 2008, 19:18

@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

Freitag 8. Februar 2008, 19:47

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:

Freitag 8. Februar 2008, 20:03

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: 4871
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Freitag 8. Februar 2008, 20:33

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

Freitag 8. Februar 2008, 20:47

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

Freitag 8. Februar 2008, 20:55

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: 4871
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Freitag 8. Februar 2008, 21:12

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

Freitag 8. Februar 2008, 21:30

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
Antworten