Seite 1 von 1

Unicode in Datei schreiben

Verfasst: Freitag 27. März 2009, 17:57
von Maikell
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))

Verfasst: Freitag 27. März 2009, 18:00
von Darii
Hast du in der Python-Datei selbst auch eine Zeichenkodierung angegeben und die Datei entsprechend abgespeichert?

Verfasst: Freitag 27. März 2009, 18:10
von Maikell
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. :(

Verfasst: Freitag 27. März 2009, 18:22
von Maikell
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!

Verfasst: Freitag 27. März 2009, 19:07
von Maikell
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?

Verfasst: Freitag 27. März 2009, 19:21
von Hyperion
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!)

Verfasst: Freitag 27. März 2009, 19:58
von b.esser-wisser
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.

Verfasst: Freitag 27. März 2009, 20:20
von Maikell
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!

Verfasst: Freitag 27. März 2009, 20:48
von b.esser-wisser
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.

Verfasst: Freitag 27. März 2009, 21:46
von 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.

Verfasst: Freitag 27. März 2009, 22:50
von b.esser-wisser
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

Verfasst: Samstag 28. März 2009, 00:48
von Maikell
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

Verfasst: Samstag 28. März 2009, 05:35
von 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.

Verfasst: Samstag 28. März 2009, 06:52
von snafu
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'

Verfasst: Samstag 28. März 2009, 10:01
von 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.

Verfasst: Samstag 28. März 2009, 11:45
von b.esser-wisser
@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?

Verfasst: Samstag 28. März 2009, 12:08
von 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.

Verfasst: Samstag 28. März 2009, 12:45
von Maikell
Danke!

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

Vielen Dank!