2016-07-14 75 views
7

questa è la mia prima volta che utilizzo StackOverflow per fare una domanda, ma hai salvato collettivamente tanti dei miei progetti nel corso degli anni che Mi sento già a casa.Python 3.5 UnicodeDecodeError per un file in utf-8 (lingua è 'ang', inglese antico)

Sto usando Python3.5 e nltk per analizzare il corpus completo del vecchio inglese, che è stato pubblicato per me come 77 file di testo e un documento XML che designa la sequenza di file come segmenti contigui di un corpus in formato TEI. Ecco la parte rilevante del colpo di testa da proiezione doc XML che siamo, infatti, lavorando con TEI:

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

Giusto, quindi come un test, sto solo cercando di usare MTECorpusReader di NLTK per aprire il corpus e usa il metodo words() per dimostrare che sono in grado di aprirlo. Sto facendo tutto questo dalla shell Python interattiva, solo per facilità di test. Ecco tutto quello che sto facendo davvero:

# 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() 

Quando provo che, ricevo il seguente traceback:

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 

Così, come io sono uno StackOverflowsketeer coraggioso, ho stabilito che uno dei due o più file sono corrotti o c'è qualche carattere nel file (s) che contiene un carattere che il decodificatore utf-8 di Python non sa come gestire. Posso essere abbastanza certi dell'integrità di questo file (prendere la mia parola per esso), quindi sto perseguendo

ho provato quanto segue per riformattare i file di testo 77 senza alcun effetto apparente:

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)] 

Quindi il mio domande sono:

1) Il mio approccio finora ha senso, o ho rovinato qualcosa nella mia risoluzione dei problemi fino ad ora?

2) È giusto concludere a questo punto che il problema deve essere con il documento XML, in base al fatto che l'errore UTF-8 si presenta molto presto (in posizione esadecimale 59) e il fatto che il mio utf -8 Lo script di sostituzione dell'errore non ha fatto alcuna differenza rispetto al problema? Se ho torto a pensarlo, allora come posso isolare meglio il problema?

3) Se possiamo concludere che il problema è con il documento XML, qual è il modo migliore per chiarirlo? È possibile per me provare a trovare quel byte esadecimale e l'ASCII a cui corrisponde e modificare il carattere?

Grazie in anticipo per il vostro aiuto!

+0

Una cosa da provare: se si apre il documento in un editor di testo o un browser Web che rileva automaticamente le codifiche dei caratteri, quale codifica pensa che sia il documento? –

+1

Sembra infatti che il file XML non sia un file UTF-8 valido. Solo una supposizione per risolvere questo problema: trova la codifica effettiva del file (che sarà la parte fastidiosa), leggi il file come testo normale con quella codifica, quindi salvalo come UTF-8 e potresti finire con un UTF valido -8 file XML codificato. A condizione che non ci siano sezioni binarie (CDATA) nel file XML. – Evert

+0

Ciao a tutti - grazie per aver confermato i miei sospetti sul documento XML. Quindi l'intestazione nella parte superiore del documento XML specifica che la sua codifica è utf-8, e infatti sono in grado di aprirlo in Sublime Text con la codifica UTF-8. Mi chiedo se i miei strumenti funzionino un po 'troppo bene qui e convertiremo automaticamente le codifiche per me ... Ci giocherò un po' di più, ma finora i miei tentativi di salvare la codifica come UTF-8 da vari gli editori non fanno alcuna differenza. – gatsbysghost

risposta

4

La tua tecnica di conversione non ha funzionato perché non hai mai letto e scritto di nuovo il file.

0x80 non è un byte valido in UTF-8 o qualsiasi iso-8859- * set di caratteri. È valido nelle codepage di Windows, ma solo Unicode può supportare i caratteri Old English, quindi hai alcuni dati molto rotti.

Per convertire UTF-8 con cattive byte fare:

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()) 

Se non si cura di perdere i dati, è possibile ottenere via utilizzando l'argomento encoding su MTECorpusReader:

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

che renderà 0x80 un simbolo Euro (€).

+1

mi chiedo quanti di quelli che troverà nei testi in inglese antico! – patrick

+0

Ah, sì, sapevo che qualcosa non andava nel modo in cui stavo cercando di riformattare i set di caratteri nei file. Grazie mille per avermi aiutato a correggere la mia ignoranza Python - sto ancora imparando! – gatsbysghost

+0

Questo è tutto corretto, ma poiché il corpus è piuttosto vecchio, è molto probabile che usi un set di caratteri base 8-it con estensioni personalizzate per i simboli mancanti (ð, þ ecc.). Probabilmente è nella documentazione fornita con il corpus, ma in caso contrario, non dovrebbe essere difficile capire il significato di ogni byte personalizzato esaminando il file, se si conosce anche un po 'l'Old English. Perché non provi a farlo e torna con una domanda su come convertire un file da una codifica a 8 bit personalizzata in Unicode (è piuttosto semplice). – alexis

0

Unicode non è supportato in NLTK. Affatto. Sospetto che, se è un vecchio inglese, avrà bisogno di usare alcune strane lettere.

C'è, tuttavia, una soluzione che può ridurre il mal di testa. C'è una libreria molto più moderna e potente di NLTK, chiamata spacy. Here's a link.

richieste

Spacy che tutto Unicode, mentre NLTK richiede che tutto non essere. Non vale il mal di testa coinvolto. Inoltre, il processore NLTK solo funziona su stringhe completamente prive di Unicode, che possono dare risultati incasinati.

+2

Come hai accertato che il personaggio era 'À'? –

+0

Leggere attentamente l'errore. Il codec "utf-8" non può decodificare il byte 0x80 nella posizione 59' È un byte non valido in utf-8. Quindi non può capire di cosa si tratta. Ma il vicino più vicino è un personaggio di controllo o quel simbolo. – Ares

+1

In quale set di caratteri è 'À' il carattere più vicino a' 0x80'? –