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'

874voto

Tim Swast Punkte 13064

Anstatt sich mit den Kodierungs- und Dekodierungsmethoden herumzuschlagen, finde ich es einfacher, die Kodierung beim Öffnen der Datei anzugeben. Die io Modul (hinzugefügt in Python 2.6) bietet eine io.open Funktion, die einen Kodierungsparameter hat.

Verwenden Sie die Methode open aus der io Modul.

>>>import io
>>>f = io.open("test", mode="r", encoding="utf-8")

Nach dem Aufruf der Funktion read() von f wird dann ein kodiertes Unicode-Objekt zurückgegeben.

>>>f.read()
u'Capit\xe1l\n\n'

Beachten Sie, dass in Python 3 die io.open Funktion ist ein Alias für die eingebaute open Funktion. Die eingebaute Funktion open unterstützt das Argument encoding nur in Python 3, nicht in Python 2.

Edit: Zuvor empfahl diese Antwort die Codecs Modul. Die Website Codec-Modul kann beim Mischen Probleme verursachen read() y readline() so empfiehlt diese Antwort nun die io Modul stattdessen.

Verwenden Sie die Methode open des Codecs-Moduls.

>>>import codecs
>>>f = codecs.open("test", "r", "utf-8")

Nach dem Aufruf der Funktion read() von f wird dann ein kodiertes Unicode-Objekt zurückgegeben.

>>>f.read()
u'Capit\xe1l\n\n'

Wenn Sie die Kodierung einer Datei kennen, wird die Verwendung des Codecs-Pakets viel weniger verwirrend sein.

Siehe http://docs.python.org/library/codecs.html#codecs.open

122voto

In der Notation

u'Capit\xe1n\n'

die " \xe1 " steht für ein einziges Byte. " \x " sagt Ihnen, dass "e1" in hexadezimaler Form vorliegt. Wenn Sie schreiben

Capit\xc3\xa1n

in Ihrer Datei haben Sie " \xc3 " darin. Das sind 4 Bytes, und in Ihrem Code lesen Sie sie alle. Sie können dies sehen, wenn Sie sie anzeigen:

>>> open('f2').read()
'Capit\\xc3\\xa1n\n'

Sie können sehen, dass der Backslash durch einen Backslash ersetzt wird. Sie haben also vier Bytes in Ihrer Zeichenkette: "\", "x", "c" und "3".

Edit :

Wie andere in ihren Antworten bereits erwähnt haben, sollten Sie die Zeichen einfach in den Editor eingeben. Ihr Editor sollte dann die Konvertierung in UTF-8 vornehmen und die Datei speichern.

Wenn Sie tatsächlich eine Zeichenkette in diesem Format haben, können Sie die string_escape Codec, um sie in eine normale Zeichenkette zu dekodieren:

In [15]: print 'Capit\\xc3\\xa1n\n'.decode('string_escape')
Capitán

Das Ergebnis ist eine Zeichenkette, die in UTF-8 kodiert ist, wobei das akzentuierte Zeichen durch die beiden geschriebenen Bytes dargestellt wird \\xc3\\xa1 in der ursprünglichen Zeichenfolge. Wenn Sie eine Unicode-Zeichenkette haben möchten, müssen Sie sie erneut mit UTF-8 dekodieren.

Zu Ihrer Bearbeitung: Sie haben kein UTF-8 in Ihrer Datei. Um tatsächlich zu sehen, wie es aussehen würde:

s = u'Capit\xe1n\n'
sutf8 = s.encode('UTF-8')
open('utf-8.out', 'w').write(sutf8)

Vergleichen Sie den Inhalt der Datei utf-8.out auf den Inhalt der Datei, die Sie mit Ihrem Editor gespeichert haben.

83voto

Dakusan Punkte 6255

Jetzt brauchen Sie in Python3 nur noch open(Filename, 'r', encoding='utf-8')

[Bearbeiten am 2016-02-10 für gewünschte Klarstellung]

Python3 fügte die Kodierung Parameter an die Funktion open. Die folgenden Informationen über die Öffnungsfunktion sind hier zu finden: https://docs.python.org/3/library/functions.html#open

open(file, mode='r', buffering=-1, 
      encoding=None, errors=None, newline=None, 
      closefd=True, opener=None)

Kodierung ist der Name der zur Dekodierung verwendeten Kodierung Datei. Dies sollte nur im Textmodus verwendet werden. Die Standardkodierung ist plattformabhängig (was auch immer locale.getpreferredencoding() zurückgibt), aber jede Textkodierung unterstützt von Python Siehe die Codecs Modul für die Liste der unterstützten Kodierungen.

Durch Hinzufügen von encoding='utf-8' als Parameter für die Funktion open angeben, werden alle Lese- und Schreibvorgänge in utf8 durchgeführt (was jetzt auch die Standardkodierung für alles ist, was in Python gemacht wird).

20voto

Sina Punkte 401

Tatsächlich funktionierte dies für mich zum Lesen einer Datei mit UTF-8-Kodierung in Python 3.2:

import codecs
f = codecs.open('file_name.txt', 'r', 'UTF-8')
for line in f:
    print(line)

18voto

Gregg Lind Punkte 19744

Ich habe also eine Lösung für das gefunden, was ich suche, nämlich:

print open('f2').read().decode('string-escape').decode("utf-8")

Es gibt einige ungewöhnliche Codecs, die hier nützlich sind. Diese spezielle Lesung ermöglicht es, UTF-8-Darstellungen aus Python zu übernehmen, sie in eine ASCII-Datei zu kopieren und sie in Unicode einzulesen. Bei der "string-escape"-Dekodierung werden die Schrägstriche nicht verdoppelt.

Dies ermöglicht die Art von Rundreise, die ich mir vorgestellt habe.

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