2016-07-14 9 views
7

Dies ist das erste Mal, dass ich StackOverflow benutze, um eine Frage zu stellen, aber Sie haben im Laufe der Jahre so viele meiner Projekte gespeichert Ich fühle mich schon zuhause.Python 3.5 UnicodeDecodeError für eine Datei in utf-8 (Sprache ist 'ang', Old English)

Ich benutze Python3.5 und nltk, um das Complete Corpus von Old English zu analysieren, das als 77 Textdateien und ein XML-Dokument veröffentlicht wurde, das die Dateisequenz als zusammenhängende Segmente eines TEI-formatierten Corpus bezeichnet. Hier ist der relevante Teil des Headers aus dem XML-Dokument zeigt, dass wir in der Tat mit TEI arbeiten:

<?xml version="1.0" encoding="UTF-8"?> 
<TEI xmlns="http://www.tei-c.org/ns/1.0"> 
    <teiHeader type="ISBD-ER"> 
    <fileDesc> 

Recht, so als Test, ich versuche nur NLTK die MTECorpusReader zum Öffnen des Korpus zu verwenden und benutze die words() Methode, um zu beweisen, dass ich sie öffnen kann. Ich mache all das aus der interaktiven Python-Shell, nur um das Testen zu vereinfachen. Hier ist alles, was ich wirklich tun:

# import the reader method  
import nltk.corpus.reader as reader 

# open the sequence of files and the XML doc with the MTECorpusReader  
oecorpus = reader.mte.MTECorpusReader('/Users/me/Documents/0163','.*') 

# print the first few words in the corpus to the interactive shell 
oecorpus.words() 

Wenn ich versuche, dass ich die folgende Zurückverfolgungs erhalten:

Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/nltk/util.py", line 765, in __repr__ 
    for elt in self: 
    File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/nltk/corpus/reader/util.py", line 397, in iterate_from 
    for tok in piece.iterate_from(max(0, start_tok-offset)): 
    File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/nltk/corpus/reader/util.py", line 291, in iterate_from 
    tokens = self.read_block(self._stream) 
    File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/nltk/corpus/reader/mte.py", line 25, in read_block 
    return list(filter(lambda x: x is not None, XMLCorpusView.read_block(self, stream, tagspec, elt_handler))) 
    File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/nltk/corpus/reader/xmldocs.py", line 307, in read_block 
    xml_fragment = self._read_xml_fragment(stream) 
    File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/nltk/corpus/reader/xmldocs.py", line 252, in _read_xml_fragment 
    xml_block = stream.read(self._BLOCK_SIZE) 
    File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/nltk/data.py", line 1097, in read 
    chars = self._read(size) 
    File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/nltk/data.py", line 1367, in _read 
    chars, bytes_decoded = self._incr_decode(bytes) 
    File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/nltk/data.py", line 1398, in _incr_decode 
    return self.decode(bytes, 'strict') 
    File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/encodings/utf_8.py", line 16, in decode 
    return codecs.utf_8_decode(input, errors, True) 
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x80 in position 59: invalid start byte 

So, wie ich einen tapferen StackOverflowsketeer bin, habe ich festgestellt, dass entweder ein oder mehr Dateien sind beschädigt oder es gibt ein Zeichen in der Datei (en), das ein Zeichen enthält, mit dem Pythons utf-8-Decoder nicht umgehen kann. Ich kann ziemlich sicher sein, der diese Integrität der Datei (mein Wort nehmen), so dass ich verfolge

Ich hat versucht, die im Anschluss an die 77 Textdateien ohne erkennbare Wirkung zu formatieren:

for file in loglist: 
    bufferfile = open(file, encoding='utf-8', errors='replace') 
    bufferfile.close() 
loglist = [name for name in os.listdir('.') if os.path.isfile(name)] 

Also meine Fragen sind:

1) Ist mein Ansatz soweit sinnvoll, oder habe ich bei meiner Fehlersuche bisher etwas vermasselt?

2) Ist es fair, an dieser Stelle zu schließen, dass das Problem mit dem XML-Dokument sein muss, basierend auf der Tatsache, dass der UTF-8-Fehler sehr früh auftaucht (an Hex-Position 59) und die Tatsache, dass meine utf -8 Fehler Ersetzung Skript machte keinen Unterschied für das Problem? Wenn ich das falsch vermute, wie kann ich das Problem dann besser isolieren?

3) Wenn wir feststellen, dass das Problem mit dem XML-Dokument zu tun hat, was ist der beste Weg, um es zu löschen? Ist es möglich für mich zu versuchen, dieses Hexadezimalbyte und das ASCII zu finden, dem es entspricht und das Zeichen zu ändern?

Vielen Dank im Voraus für Ihre Hilfe!

+0

Eine Sache, die Sie ausprobieren sollten: Wenn Sie das Dokument in einem Texteditor oder Webbrowser öffnen, der Zeichencodierungen automatisch erkennt, für welche Codierung hält es das Dokument? –

+1

Es sieht so aus, als wäre die XML-Datei keine gültige UTF-8-Datei. Nur eine Vermutung, um dies zu lösen: Finden Sie die tatsächliche Codierung der Datei (das wird der lästige Teil sein), lesen Sie die Datei als Nur-Text mit dieser Codierung, dann speichern Sie es als UTF-8 und Sie könnten mit einem gültigen UTF enden -8 codierte XML-Datei. Vorausgesetzt, es gibt keine binären (CDATA) Abschnitte in der XML-Datei. – Evert

+0

Hey alle - danke für die Bestätigung meiner Vermutungen über das XML-Dokument. Die Überschrift oben im XML-Dokument gibt an, dass die Codierung utf-8 ist, und ich kann sie in Sublime Text mit UTF-8-Codierung öffnen. Ich frage mich, ob meine Tools hier tatsächlich ein bisschen zu gut funktionieren und die Encodings für mich automatisch umwandeln ... Ich werde damit ein bisschen mehr herumspielen, aber bisher versuche ich die Codierung als UTF-8 von verschiedenen zu speichern Redakteure macht keinen Unterschied. – gatsbysghost

Antwort

4

Ihre Konvertierungstechnik hat nicht funktioniert, weil Sie die Datei nie wieder gelesen und geschrieben haben.

0x80 ist kein gültiges Byte in UTF-8 oder einem iso-8859- * Zeichensatz. Es ist in Windows-Codepages gültig, aber nur Unicode kann alte englische Zeichen unterstützen, sodass Sie einige sehr defekte Daten haben.

UTF-8 mit schlechtem Bytes konvertieren tun:

with open('input.txt', 'r', encoding='utf-8', errors='ignore') as input, 
     open('output.txt', 'w', encoding='utf-8') as output: 

    output.write(input.read()) 

Wenn Sie nicht über den Verlust von Daten ist es egal, Sie wegkommen können auf MTECorpusReader das encoding Argument:

oecorpus = reader.mte.MTECorpusReader('/Users/me/Documents/0163','.*', encoding='cp1252') 

die macht 0x80 ein Euro (€) Symbol.

+1

Ich frage mich, wie viele von denen er in alten englischen Texten finden wird! – patrick

+0

Ah, ja, ich wusste, dass etwas nicht in Ordnung war mit der Art, wie ich die Zeichensätze in den Dateien neu formatieren wollte. Vielen Dank, dass Sie mir geholfen haben, meine Python-Ignoranz zu korrigieren - ich lerne immer noch! – gatsbysghost

+0

Das ist alles in Ordnung, aber da das Korpus ziemlich alt ist, wird sehr wahrscheinlich ein Basis-8-It-Zeichensatz mit benutzerdefinierten Erweiterungen für die fehlenden Symbole (ð, þ usw.) verwendet. Es ist wahrscheinlich in der Dokumentation, die mit dem Korpus kam, aber wenn nicht, sollte es nicht schwer, die Bedeutung jedes benutzerdefinierten Byte herauszufinden, indem Sie die Datei untersuchen, wenn Sie sogar ein wenig Old English wissen. Warum probierst du das nicht aus und kommst zurück mit einer Frage, wie man eine Datei von einer benutzerdefinierten 8-Bit-Kodierung in Unicode konvertiert (das ist ziemlich einfach). – alexis

0

Unicode wird in NLTK nicht unterstützt. Überhaupt. Ich vermute, wenn es sich um ein altes Englisch handelt, wird es einige seltsame Buchstaben brauchen.

Es gibt jedoch eine Lösung, die Kopfschmerzen minimieren kann. Es gibt eine Bibliothek, die wesentlich moderner und leistungsfähiger ist als NLTK, genannt spacy. Here's a link.

Spacy verlangt, dass alles Unicode seiner, während NLTK verlangt, dass alles nicht sein. Es ist die Kopfschmerzen nicht wert. Plus, NLTKs Prozessor wird nur arbeiten vollständig Unicode-freie Zeichenfolgen, die einige verwirrte Ergebnisse geben kann.

+2

Wie hast du festgestellt, dass der Charakter "À" war? –

+0

Lesen Sie den Fehler sorgfältig. ''utf-8' Codec kann Byte 0x80 in Position 59' nicht decodieren Es ist ein ungültiges Byte in utf-8. So kann es nicht herausfinden, was es ist. Aber der nächste Nachbar ist entweder ein Kontrollzeichen oder das Symbol. – Ares

+1

In welchem ​​Zeichensatz ist 'À' das nächstliegende Zeichen zu '0x80'? –