410 Stimmen

Unicode (UTF-8) Lesen und Schreiben von Dateien in Python

Ich habe einige Gehirn Fehler im Verständnis Lesen und Schreiben von Text in eine Datei (Python 2.4).

# The string, which has an a-acute in it.
ss = u'Capit\xe1n'
ss8 = ss.encode('utf8')
repr(ss), repr(ss8)

("u'Capit \xe1n '", "'Capit \xc3\xa1n '")

print ss, ss8
print >> open('f1','w'), ss8

>>> file('f1').read()
'Capit\xc3\xa1n\n'

Ich gebe also ein Capit\xc3\xa1n in meinem Lieblingseditor, in der Datei f2.

Dann:

>>> open('f1').read()
'Capit\xc3\xa1n\n'
>>> open('f2').read()
'Capit\\xc3\\xa1n\n'
>>> open('f1').read().decode('utf8')
u'Capit\xe1n\n'
>>> open('f2').read().decode('utf8')
u'Capit\\xc3\\xa1n\n'

Was verstehe ich hier nicht? Offensichtlich gibt es einen wichtigen Teil der Magie (oder des gesunden Menschenverstands), den ich übersehe. Was muss man in Textdateien eingeben, damit sie richtig konvertiert werden?

Was ich hier wirklich nicht verstehe, ist, was der Sinn der UTF-8-Darstellung ist, wenn man Python nicht dazu bringen kann, sie zu erkennen, wenn sie von außen kommt. Vielleicht sollte ich einfach JSON dump die Zeichenfolge, und verwenden, dass stattdessen, da das eine asciiable Darstellung hat! Genauer gesagt, gibt es eine ASCII-Darstellung dieses Unicode-Objekts, die Python erkennt und dekodiert, wenn es aus einer Datei kommt? Wenn ja, wie bekomme ich sie?

>>> print simplejson.dumps(ss)
'"Capit\u00e1n"'
>>> print >> file('f3','w'), simplejson.dumps(ss)
>>> simplejson.load(open('f3'))
u'Capit\xe1n'

14voto

Ricardo Punkte 588
# -*- encoding: utf-8 -*-

# converting a unknown formatting file in utf-8

import codecs
import commands

file_location = "jumper.sub"
file_encoding = commands.getoutput('file -b --mime-encoding %s' % file_location)

file_stream = codecs.open(file_location, 'r', file_encoding)
file_output = codecs.open(file_location+"b", 'w', 'utf-8')

for l in file_stream:
    file_output.write(l)

file_stream.close()
file_output.close()

9voto

Ryan Punkte 187

Mit Ausnahme von codecs.open() kann man verwenden io.open() mit Python2 oder Python3 zu arbeiten, um Unicode-Dateien zu lesen/schreiben

Beispiel

import io

text = u'á'
encoding = 'utf8'

with io.open('data.txt', 'w', encoding=encoding, newline='\n') as fout:
    fout.write(text)

with io.open('data.txt', 'r', encoding=encoding, newline='\n') as fin:
    text2 = fin.read()

assert text == text2

6voto

Torsten Marek Punkte 78610

Nun, Ihr bevorzugter Texteditor erkennt nicht, dass \xc3\xa1 sollen eigentlich Zeichenliterale sein, werden aber als Text interpretiert. Deshalb erhalten Sie die doppelten Backslashes in der letzten Zeile - es ist jetzt ein echter Backslash + xc3 usw. in Ihrer Datei.

Wenn Sie kodierte Dateien in Python lesen und schreiben wollen, verwenden Sie am besten die Codecs Modul.

Das Einfügen von Text zwischen dem Terminal und Anwendungen ist schwierig, weil man nicht weiß, welches Programm den Text in welcher Kodierung interpretiert. Sie könnten Folgendes versuchen:

>>> s = file("f1").read()
>>> print unicode(s, "Latin-1")
Capitán

Fügen Sie diese Zeichenkette dann in Ihren Editor ein und stellen Sie sicher, dass er sie in Latin-1 speichert. Unter der Annahme, dass die Zwischenablage die Zeichenfolge nicht verstümmelt, sollte der Hin- und Rückweg funktionieren.

6voto

Aaron Digulla Punkte 308693

Sie sind über das allgemeine Problem mit Kodierungen gestolpert: Wie kann ich feststellen, in welcher Kodierung eine Datei vorliegt?

Antwort: Sie können nicht es sei denn, das Dateiformat sieht dies vor. XML zum Beispiel beginnt mit:

<?xml encoding="utf-8"?>

Diese Kopfzeile wurde sorgfältig ausgewählt, damit sie unabhängig von der Kodierung gelesen werden kann. In Ihrem Fall gibt es keinen solchen Hinweis, so dass weder Ihr Editor noch Python eine Ahnung davon haben, was vor sich geht. Daher müssen Sie die codecs Modul und verwenden codecs.open(path,mode,encoding) die das fehlende Bit in Python liefert.

Was Ihren Editor betrifft, müssen Sie prüfen, ob er eine Möglichkeit bietet, die Kodierung einer Datei einzustellen.

Der Sinn von UTF-8 besteht darin, 21-Bit-Zeichen (Unicode) als 8-Bit-Datenstrom zu kodieren (denn das ist das Einzige, was alle Computer der Welt verarbeiten können). Da aber die meisten Betriebssysteme aus der Zeit vor der Unicode-Ära stammen, verfügen sie nicht über geeignete Werkzeuge, um die Kodierungsinformationen an Dateien auf der Festplatte anzuhängen.

Das nächste Problem ist die Darstellung in Python. Dies wird perfekt erklärt in der Kommentar von heikogerlach . Sie müssen wissen, dass Ihre Konsole nur ASCII anzeigen kann. Um Unicode oder irgendetwas >= Zeichencode 128 anzeigen zu können, muss sie irgendeine Art von Escaping verwenden. In Ihrem Editor müssen Sie nicht die maskierte Zeichenfolge eingeben, sondern die Bedeutung der Zeichenfolge (in diesem Fall müssen Sie die Umlaute eingeben und die Datei speichern).

Sie können jedoch die Python-Funktion eval() verwenden, um eine maskierte Zeichenkette in eine Zeichenkette zu verwandeln:

>>> x = eval("'Capit\\xc3\\xa1n\\n'")
>>> x
'Capit\xc3\xa1n\n'
>>> x[5]
'\xc3'
>>> len(x[5])
1

Wie Sie sehen können, ist die Zeichenfolge " \xc3 " wurde in ein einzelnes Zeichen umgewandelt. Dies ist nun eine 8-Bit-Zeichenkette, UTF-8 kodiert. Um Unicode zu erhalten:

>>> x.decode('utf-8')
u'Capit\xe1n\n'

Gregg Lind gefragt: Ich glaube, hier fehlen einige Teile: Die Datei f2 enthält: hex:

0000000: 4361 7069 745c 7863 335c 7861 316e  Capit\xc3\xa1n

codecs.open('f2','rb', 'utf-8') Gibt es irgendeine Möglichkeit, in eine Datei in ASCII zu schreiben, die funktionieren würde?

Antwort: Das hängt davon ab, was Sie meinen. ASCII kann keine Zeichen > 127 darstellen. Sie brauchen also eine Möglichkeit zu sagen: "Die nächsten Zeichen bedeuten etwas Besonderes", was die Sequenz " \x " tut. Sie sagt: Die nächsten zwei Zeichen sind der Code eines einzelnen Zeichens. " \u " macht das Gleiche mit vier Zeichen, um Unicode bis 0xFFFF (65535) zu kodieren.

Man kann also nicht direkt Unicode in ASCII schreiben (weil ASCII einfach nicht die gleichen Zeichen enthält). Sie können sie als String-Escapes schreiben (wie in f2); in diesem Fall kann die Datei als ASCII dargestellt werden. Oder Sie können sie als UTF-8 schreiben; in diesem Fall benötigen Sie einen sicheren 8-Bit-Stream.

Ihre Lösung mit decode('string-escape') funktioniert, aber Sie müssen sich darüber im Klaren sein, wie viel Speicherplatz Sie verwenden: Dreimal so viel wie bei der Verwendung von codecs.open() .

Denken Sie daran, dass eine Datei nur eine Folge von Bytes mit 8 Bits ist. Weder die Bits noch die Bytes haben eine Bedeutung. Sie sind es, der sagt: "65 bedeutet 'A'". Seit \xc3\xa1 zu "à" werden soll, aber der Computer keine Möglichkeit hat, dies zu erkennen, müssen Sie ihm die Kodierung mitteilen, die beim Schreiben der Datei verwendet wurde.

6voto

praj Punkte 61

Um eine Unicode-Zeichenkette einzulesen und dann an HTML zu senden, habe ich Folgendes getan:

fileline.decode("utf-8").encode('ascii', 'xmlcharrefreplace')

Nützlich für pythonbetriebene http-Server.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X