Unicode in Datei schreiben

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
Maikell
User
Beiträge: 11
Registriert: Donnerstag 19. März 2009, 16:23

Hallo!

Kurze Frage:

Ich will eine Liste (words) in eine Datei schreiben. Die Elemente der Datei sind UTF-16 codiert und enthalten deutsche Umlaute!

Code: Alles auswählen

data2 = codecs.open("Dateiname.txt","w",encoding="UTF-16LE")
data2.write(u"Test! Bläbläblä - kein problem!")
while i < len(words):
     data2.write(str(words[i]))
     data2.write("\n")
     i = i + 1

Aber er wirft mir folgende Exception:

line 196, in printStats
data2.write(str(words))
UnicodeEncodeError: 'ascii' codec can't encode character u'\xdf' in position 2: ordinal not in range(128)





Wie kann ich Python sagen, dass er die Liste mit den Umlauten in die Datei schreiben soll?
Wenn ich sie auf der Konsole ausgeben will, amch ich einfach ein "u" vor den String. Nur wo mache ich das "u" in diesem Fall hin?
data2.write(str(words))
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Hast du in der Python-Datei selbst auch eine Zeichenkodierung angegeben und die Datei entsprechend abgespeichert?
Maikell
User
Beiträge: 11
Registriert: Donnerstag 19. März 2009, 16:23

Danke für die Antwort.
Was genau meinst du? In der obersten Zeile steht "# -*- coding: utf-8 -*-"
Meinst du das?
Wenn ich da utf-16 reinschreibe, geht leider gar nichts. :(
Maikell
User
Beiträge: 11
Registriert: Donnerstag 19. März 2009, 16:23

ok, wenn ich es statt

Code: Alles auswählen

data2.write(str(words[i]))
so schreibe:

Code: Alles auswählen

data2.write(unicode(words[i]))
Dann funktioniert es teilweise! Er schreibt die Liste in die Datei. Nur leider schreibt er dann den String "\n" nicht mehr dazu! Was die Ausgabedatei ziemlich unünbersichtlich macht!
Maikell
User
Beiträge: 11
Registriert: Donnerstag 19. März 2009, 16:23

Seufz... keiner ne Idee?

Das Programm schreibt mir zwar die Listeninhalte in die Datei, aber wenn ich die Datei mit dem Editor öffne, fehlen alle Zielenumbrüche!("\n")

Wie bekomme ich diese wieder dazu?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Wieso übergibst Du write eigentlich einen Unicode String? Laut Doku soll da doch ein Bytestring rein? Ich hätte da jetzt so etwas vermutet:

Code: Alles auswählen

data2.write(unicode(words[i]).encode("utf-16"))
@experts:
Wie wandelt Python das dort dann an dieser Stelle? Nimmt er die Codierung des Quelltextes oder erkennt er anhand des File-Objects, welches Encoding verwendet werden soll? (Also in der Ursprungslösung!)
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

das "coding-cookie" (# ... coding:xxx) gilt nur für unicode-literals (u"rabarber"), für alles andere muss das encoding (nochmal, extra) angegeben werden.

Code: Alles auswählen

#Also entweder
with open(FILENAME, "w") as text_file:
  text = u"Hallo öde Welt".encode("utf-16le") #<encoding
  text_file.write(text)
#oder:
with codecs.open(FILENAME, "w", "utf-16le") as text_file: #<encoding
  text_file.write(u"Hallo öde Welt")
Wobei letzeres IMHO praktischer ist, denn man soll ja so früh wie möglich decoden (in unicode()-objekte umwandeln) und so spät wie möglich encoden (mit dem codecs-modul, vom Datenbank-/GUI-Modul wandeln lassen, usw).

hth, Jörg der hart für seinen Nickname arbeitet ;)
ps.:
Hyperion hat geschrieben: Wieso übergibst Du write eigentlich einen Unicode String?
Das ist bei Verwendung von codecs.open() schon richtig so.
Wir haben schon 10% vom 21. Jahrhundert hinter uns!
Maikell
User
Beiträge: 11
Registriert: Donnerstag 19. März 2009, 16:23

Danke für die Antworten!

Leider weiß ich immer noch nicht, wie ich Zeilenumbrüche in meine Datei bekomme!

weder
data.write("\n")
noch
data.write(u"\n")

funktionierten! Das "\n" wird einfach ignoriert! Vorschläge?

Achja: Konsolenausgabe funktioniert wunderbar! Auch mit den Zeilenumbrüchen!
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

Das sollte schon funktionieren:

Code: Alles auswählen

In [1]: import codecs

In [2]: FILE = r"utest.txt"

In [3]: f=codecs.open(FILE, "w", "utf-16le")

In [4]: f.write(u"Hallo\nPython-\nistas")

In [5]: f.close()

In [6]: f=codecs.open(FILE, "r", "utf-16le")

In [7]: print f.read()
Hallo
Python-
istas

In [8]:
hth, Jörg
ps.: Falls du file.writelines() benutzen willst, musst du die newline-zeichen einbauen
pps.: Und nicht vergessen: die Datei schließen und im richtigen Modus zum lesen neu öffnen.
Wir haben schon 10% vom 21. Jahrhundert hinter uns!
BlackJack

Vielleicht ist das Problem ja auch das Programm mit dem Maikell die Datei danach anschaut? Vielleicht mag das ein einfaches '\n' nicht, sondern möchte Windows-Zeilentrenner haben.
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

Scheinbar funktioniert da wirklich was nicht richtig:

Code: Alles auswählen

In [39]: f = codecs.open(FILENAME, "w", "utf-16le")

In [40]: f.write(u"Hallo\nPython\nWelt")

In [41]: f.close()
schreibt (python 2.5.4/WindowsXp 32) wörtlich:

Code: Alles auswählen

In [44]: f = open(FILE, "rb")

In [45]: print f.read()[:12].encode("hex")
#480061006c006c006f000a005000
#H   a   l   l   o   \n  P   
Das ist das unixoide Zeilenende.
Die andere Methode ist nicht wirklich besser:

Code: Alles auswählen

In [54]: f = open(FILE, "w")

In [55]: f.write(u"Hallo\nPython\nWelt".encode("utf-16le"))

In [56]: f.close()

In [57]: f = open(FILE, "rb")

In [58]: print f.read()[:12].encode("hex")
#480061006c006c006f000d0a0050
#H   a   l   l   o   \r\n  P
Das ist doch auch falsch, müsste das Zeilenende nicht "\r\x00\n\x00" (d.h. zwei Bytes pro Zeichen) sein?
Ich recherchiere weiter
hth, Jörg
edit: spacing
Wir haben schon 10% vom 21. Jahrhundert hinter uns!
Maikell
User
Beiträge: 11
Registriert: Donnerstag 19. März 2009, 16:23

Vielleicht ist das Problem ja auch das Programm mit dem Maikell die Datei danach anschaut? Vielleicht mag das ein einfaches '\n' nicht, sondern möchte Windows-Zeilentrenner haben.
Genau das ist das Problem!


Habe den Code von Jörg probiert, aber das Problem besteht weiterhin.:(

Anbei ein Screenshot der Ausgabedatei:

http://img142.imagevenue.com/img.php?im ... _252lo.jpg
BlackJack

Wenn man das Windowszeilenende haben möchte, dann muss man das halt auch schreiben.

Code: Alles auswählen

In [688]: f = codecs.open('test.txt', 'w', 'utf-16le')

In [689]: f.write(u'Hallo\r\nWelt')

In [690]: f.close()

In [691]: f = open('test.txt', 'rb')

In [692]: data = f.read()

In [693]: f.close()

In [694]: print data.encode('hex')
#480061006c006c006f000d000a00570065006c007400
#H   a   l   l   o   CR  LF  W   e   l   t
Andererseits könnte man sich auch mal Gedanken darüber machen, ob man nicht den Editor wechselt. IMHO sollte jeder vernünftige Editor mit den drei gängigen Varianten "Mac", "Unix", und "Windows" klarkommen.
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Bei vielen Zeilen bietet sich dann natürlich `join()` an:

Code: Alles auswählen

In [1]: '\r\n'.join(['zeile1', 'zeile2', 'zeile3'])
Out[1]: 'zeile1\r\nzeile2\r\nzeile3'
lunar

@b.esser-wisser
Vielleicht solltest du mal in der Dokumentation von codecs.open "recherchieren":
Files are always opened in binary mode, even if no binary mode was specified. This is done to avoid data loss due to encodings using 8-bit values. This means that no automatic conversion of '\n' is done on reading and writing.
Die Konvertierung von Zeichenenden funktioniert nur, wenn man ASCII-kompatibele Kodierungen nutzt. UTF-16 ist nicht ASCII-kompatibel, darum erzeugt die Konvertierung ungültige Daten. Daraus folgt, dass man UTF-16 binär schreiben und selbst für korrekte Zeilenenden sorgen muss.
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

@lunar: Ja, das ist mir dann auch eingefallen - im docstring zu codecs.open() stehts drin, in der 2.5-doku nicht (http://www.python.org/doc/2.5.4/lib/module-codecs.html) - aber in der von 2.6, was ich aber nicht nutze.

Um das ganze allgemein zu halten, funktioniert ein "unicode(os.linesep)" immer?
BlackJack

Definiere "funktionieren". Es kommt halt darauf an, was man in der Datei haben möchte. Was davon abhängt was das Programm, welches die Daten später lesen soll, erwartet.
Maikell
User
Beiträge: 11
Registriert: Donnerstag 19. März 2009, 16:23

Danke!

mit "\r\n" statt "\n" klappt es wunderbar! 8)

Vielen Dank!
Antworten