Lesen von Zeichen aus einer Datei in Python

102

In einer Textdatei gibt es eine Zeichenfolge "Ich mag das nicht".

Wenn ich es jedoch in eine Zeichenfolge einlese, wird es zu "Ich mag \ xe2 \ x80 \ x98t nicht so". Ich verstehe, dass \ u2018 die Unicode-Darstellung von "'" ist. ich benutze

f1 = open (file1, "r")
text = f1.read()

Befehl zum Lesen.

Ist es nun möglich, die Zeichenfolge so zu lesen, dass beim Einlesen in die Zeichenfolge "Ich mag das nicht" anstelle von "Ich mag das nicht \ xe2 \ x80 \ x98t"?

Zweite Änderung: Ich habe gesehen, dass einige Leute Mapping verwenden, um dieses Problem zu lösen. Gibt es wirklich keine integrierte Konvertierung, die diese Art der Konvertierung von ANSI in Unicode (und umgekehrt) durchführt?

Graviton
quelle
Einige Kommentare: Ich habe gesehen, dass einige Leute Mapping verwenden, um dieses Problem zu lösen, aber gibt es wirklich keine integrierte Konvertierung, die diese Art der Konvertierung von ANSI in Unicode (und umgekehrt) durchführt? Vielen Dank!
Graviton
Es gibt keine, weil es Hunderttausende von Unicode-Codepunkten gibt. Wie würden Sie entscheiden, welche welchen ASCII-Zeichen zugeordnet werden sollen?
John Millikin
2
Übrigens ist Ihre Textdatei kaputt! U + 2018 ist das "LEFT SINGLE QUOTATION MARK", kein Apostroph (am häufigsten U + 0027).
John, dein Kommentar ist falsch, zumindest im allgemeinen Sinne. Die iconv lib kann verwendet werden, um Unicode-Zeichen in ASCII zu transkribieren (auch vom Gebietsschema abhängig. $ python -c 'print u "\ u2018" .encode ("utf-8")' | iconv -t 'ascii // translit' | xxd 0000000: 270a
Die Sache ist, Sie müssen UNICODE in ASCII konvertieren (nicht umgekehrt).
Hasen

Antworten:

156

Ref: http://docs.python.org/howto/unicode

Das Lesen von Unicode aus einer Datei ist daher einfach:

import codecs
with codecs.open('unicode.rst', encoding='utf-8') as f:
    for line in f:
        print repr(line)

Es ist auch möglich, Dateien im Aktualisierungsmodus zu öffnen, sodass sowohl gelesen als auch geschrieben werden kann:

with codecs.open('test', encoding='utf-8', mode='w+') as f:
    f.write(u'\u4500 blah blah blah\n')
    f.seek(0)
    print repr(f.readline()[:1])

EDIT : Ich gehe davon aus, dass Ihr beabsichtigtes Ziel nur darin besteht, die Datei in Python richtig in eine Zeichenfolge einlesen zu können. Wenn Sie versuchen, aus Unicode in eine ASCII-Zeichenfolge zu konvertieren, gibt es keine direkte Möglichkeit, dies zu tun, da die Unicode-Zeichen nicht unbedingt in ASCII vorhanden sind.

Wenn Sie versuchen, in eine ASCII-Zeichenfolge zu konvertieren, versuchen Sie eine der folgenden Möglichkeiten:

  1. Ersetzen Sie die spezifischen Unicode-Zeichen durch ASCII-Entsprechungen, wenn Sie nur einige Sonderfälle wie dieses Beispiel behandeln möchten

  2. Verwenden Sie die unicodedataModule normalize()und die string.encode()Methode, um so gut wie möglich in das nächstgelegene ASCII-Äquivalent zu konvertieren (siehe https://web.archive.org/web/20090228203858/http://techxplorer.com/2006/07/18/converting- Unicode-to-ASCII-using-Python ):

    >>> teststr
    u'I don\xe2\x80\x98t like this'
    >>> unicodedata.normalize('NFKD', teststr).encode('ascii', 'ignore')
    'I donat like this'
Jay
quelle
3
codecsDas Modul behandelt den Universal Newlines-Modus nicht richtig. Verwenden Sie io.open()stattdessen Python 2.7+ (es ist open()in Python 3 integriert).
JFS
15

Es sind einige Punkte zu beachten.

Ein \ u2018-Zeichen wird möglicherweise nur als Fragment der Darstellung einer Unicode-Zeichenfolge in Python angezeigt, z. B. wenn Sie Folgendes schreiben:

>>> text = u'‘'
>>> print repr(text)
u'\u2018'

Wenn Sie die Unicode-Zeichenfolge einfach nur hübsch drucken möchten, verwenden Sie einfach die Unicode- encodeMethode:

>>> text = u'I don\u2018t like this'
>>> print text.encode('utf-8')
I dont like this

Um sicherzustellen, dass jede Zeile aus einer Datei als Unicode gelesen wird, verwenden Sie besser die codecs.openFunktion anstelle von nur open, mit der Sie die Codierung der Datei angeben können:

>>> import codecs
>>> f1 = codecs.open(file1, "r", "utf-8")
>>> text = f1.read()
>>> print type(text)
<type 'unicode'>
>>> print text.encode('utf-8')
I dont like this
DzinX
quelle
6

Aber es ist wirklich "Ich mag das nicht" und nicht "Ich mag das nicht". Das Zeichen u '\ u2018' ist ein völlig anderes Zeichen als "'" (und sollte visuell eher' '' entsprechen).

Wenn Sie versuchen, codierten Unicode in einfaches ASCII zu konvertieren, können Sie möglicherweise eine Zuordnung der Unicode-Interpunktion beibehalten, die Sie in ASCII übersetzen möchten.

punctuation = {
  u'\u2018': "'",
  u'\u2019': "'",
}
for src, dest in punctuation.iteritems():
  text = text.replace(src, dest)

Es gibt jedoch sehr viele Satzzeichen in Unicode , aber ich nehme an, Sie können sich darauf verlassen, dass nur einige von ihnen tatsächlich von der Anwendung verwendet werden, die die von Ihnen gelesenen Dokumente erstellt.

Logan
quelle
1
Wenn Sie die Diktatzuordnung von Unicode-Ordnungszahlen zu Unicode-Ordnungszahlen ({0x2018: 0x27, 0x2019: 0x27}) erstellen, können Sie das gesamte Diktat einfach an text.translate () übergeben, um alle Ersetzungen auf einmal durchzuführen.
Thomas Wouters
5

Es ist auch möglich, eine codierte Textdatei mit der Python 3-Lesemethode zu lesen:

f = open (file.txt, 'r', encoding='utf-8')
text = f.read()
f.close()

Mit dieser Variante müssen keine zusätzlichen Bibliotheken importiert werden

Stein
quelle
3

Abgesehen von der Tatsache, dass Ihre Textdatei fehlerhaft ist (U + 2018 ist ein linkes Anführungszeichen, kein Apostroph): iconv kann verwendet werden, um Unicode-Zeichen in ASCII zu transliterieren.

Sie müssen nach "iconvcodec" googeln, da das Modul anscheinend nicht mehr unterstützt wird und ich keine kanonische Homepage dafür finden kann.

>>> import iconvcodec
>>> from locale import setlocale, LC_ALL
>>> setlocale(LC_ALL, '')
>>> u'\u2018'.encode('ascii//translit')
"'"

Alternativ können Sie das iconvBefehlszeilenprogramm verwenden, um Ihre Datei zu bereinigen:

$ xxd foo
0000000: e280 980a                                ....
$ iconv -t 'ascii//translit' foo | xxd
0000000: 270a                                     '.

quelle
2

Es besteht die Möglichkeit, dass Sie eine Nicht-Unicode-Zeichenfolge mit Unicode-Escape-Zeichen haben, z.

>>> print repr(text)
'I don\\u2018t like this'

Das ist mir schon einmal passiert. Sie können einen unicode_escapeCodec verwenden, um die Zeichenfolge in Unicode zu dekodieren und sie dann in ein beliebiges Format zu kodieren:

>>> uni = text.decode('unicode_escape')
>>> print type(uni)
<type 'unicode'>
>>> print uni.encode('utf-8')
I dont like this
DzinX
quelle
1

Auf diese Weise zeigt Pythons Ihnen Unicode-codierte Zeichenfolgen. Aber ich denke, Sie sollten in der Lage sein, die Zeichenfolge ohne Probleme auf dem Bildschirm zu drucken oder in eine neue Datei zu schreiben.

>>> test = u"I don\u2018t like this"
>>> test
u'I don\u2018t like this'
>>> print test
I dont like this
Xardien
quelle
1

Tatsächlich ist U + 2018 die Unicode-Darstellung des Sonderzeichens. Wenn Sie möchten, können Sie Instanzen dieses Zeichens mit folgendem Code in U + 0027 konvertieren:

text = text.replace (u"\u2018", "'")

Womit schreiben Sie die Datei? f1.read()sollte eine Zeichenfolge zurückgeben, die folgendermaßen aussieht:

'I don\xe2\x80\x98t like this'

Wenn diese Zeichenfolge zurückgegeben wird, wird die Datei falsch geschrieben:

'I don\u2018t like this'
John Millikin
quelle
Es tut uns leid! Wie Sie sagten, kehrt es zurück "Ich mag \ xe2 \ x80 \ x98t nicht so"
Graviton
Das 'Ich mag das nicht \ xe2 \ x80 \ x98t', das Sie sehen, ist das, was Python als str bezeichnen würde. Es scheint die utf-8-Codierung von u'I don \ u2018t like this 'zu sein, die eine Unicode-Instanz in Python ist. Versuchen Sie, .decode ('utf-8') für den ersteren oder .encode ('utf-8') für den letzteren aufzurufen.
Logan
@hop: oops, vergessen ord () gibt dezimal statt hex zurück. Danke für den Fang.
John Millikin