2010-08-27 11 views
22

Ho un foglio di calcolo Excel che sto leggendo che contiene alcuni segni £.UnicodeEncodeError: il codec 'ascii' non può codificare il carattere u ' xa3'

quando cerco di leggerlo in utilizzando il modulo XLRD, ottengo il seguente errore:

x = table.cell_value(row, col) 
x = x.decode("ISO-8859-1") 
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa3' in position 0: ordinal not in range(128) 

Se riscrivo questo per x.encode ('utf-8') smette di generare un errore, ma sfortunatamente quando scrivo i dati da qualche altra parte (come latin-1), i segni £ sono tutti diventati confusi.

Come posso risolvere questo problema e leggere correttamente i segni £?

--- UPDATE ---

Una specie lettori hanno suggerito che non ho bisogno di decodificare affatto, o che io posso solo codificare al Latin-1 quando ho bisogno di. Il problema con questo è che ho bisogno di scrivere i dati in un file CSV alla fine, e sembra di opporsi alle stringhe non elaborate.

Se non codificare o decodificare i dati a tutti, allora questo accade (dopo ho aggiunto la stringa in un array di nome articoli):

for item in items: 
    #item = [x.encode('latin-1') for x in item] 
    cleancsv.writerow(item) 
File "clean_up_barnet.py", line 104, in <module> 
cleancsv.writerow(item) 
UnicodeEncodeError: 'ascii' codec can't encode character u'\u2022' in position 43: ordinal not in range(128) 

ottengo lo stesso errore anche se ho decommentare la linea Latin-1.

+0

Sei '.decode' -ing due volte? – katrielalex

+0

Non credo. La riga precedente è x = table.cell_value (row, col), dal modulo xlrd, però - forse sta facendo qualcosa di divertente? – AP257

risposta

9

tuo frammento di codice dice x.decode, ma si sta ottenendo un codificare errore - che significa x è Unicode già, quindi, a "decodificare", esso deve essere prima trasformato in una stringa di byte (ed è lì il codec predefinito ansi si presenta e fallisce). Nel tuo testo poi dici "se riscrivo ot a x codifica" ... che sembra implicare che tu sia do sapere x è Unicode.

Quindi che cosa si sta facendo - e che cosa si significare di fare - che codifica per un'unicode x per ottenere una stringa di codice di byte, o di decodifica di una stringa di byte in un oggetto unicode?

Trovo un peccato che si può chiamare encode su una stringa di byte, e decode su un oggetto unicode, perché trovo che sembra portare gli utenti a solo confusione ... ma almeno in questo caso sembrano gestire propagare la confusione (almeno a me ;-).

Se, come sembra, x è Unicode, quindi non si vuole "decodificare" - si consiglia di codificare esso per ottenere una stringa di byte con un certo codec, per esempio latin-1, se è quello che ti serve per qualche tipo di I/O (per il tuo uso interno del programma ti consiglio di restare sempre unicode - solo codificare/decodificare se e quando hai assolutamente bisogno di o ricevere, stringhe di byte codificate a scopo di input/output).

+1

Grazie. Suppongo che sia unicode allora - ma ho bisogno di codificarlo per scriverlo in un file CSV. Quando provo a codificarlo in Latin-1, ottengo un altro errore. Si prega di consultare il mio aggiornamento sopra ... – AP257

+1

Capito: la riga che mi serviva prima di scrivere in CSV era item = [x.encode ('mac_roman') per x in item]. Accettare questa risposta perché mi ha aiutato a capire cosa stava succedendo - grazie. – AP257

+0

@ alex-martelli Sarei felice di ricevere i tuoi consigli su [questa domanda] (http://stackoverflow.com/questions/23013236/how-to-encode-xml-into-esri-shapefiles-using-python). – JJD

2

xlrd funziona con Unicode, quindi la stringa che si ottiene è una stringa Unicode. Il simbolo £ ha il punto di codice U + 00A3, quindi la rappresentazione di detta stringa deve essere u'\xa3'. Questo è stato letto correttamente; è la stringa con cui dovresti lavorare durante il tuo programma.

Quando si scrive questa stringa (astratta, Unicode) da qualche parte, è necessario scegliere una codifica.A quel punto, devi inserire .encode nella codifica, ad esempio latin-1.


>>> book = xlrd.open_workbook("test.xls") 
>>> sh = book.sheet_by_index(0) 
>>> x = sh.cell_value(0, 0) 
>>> x 
u'\xa3' 
>>> print x 
£ 

# sample outputs (for e.g. writing to a file) 
>>> x.encode("latin-1") 
'\xa3' 
>>> x.encode("utf-8") 
'\xc2\xa3' 

# garbage, because x is already Unicode 
>>> x.decode("ascii") 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa3' in position 0: 
ordinal not in range(128) 
>>> 
+0

si prega di consultare il mio aggiornamento sopra: ottengo un errore quando provo a .encode ... – AP257

10

Per quel che vale: Sono l'autore di xlrd.

Il codice xlrd produce unicode?
Opzione 1: leggere la sezione Unicode nella parte inferiore della prima schermata di xlrd doc: Questo modulo presenta tutte le stringhe di testo come oggetti Unicode Python.
Opzione 2: print type(text), repr(text)

si dice "" "Se riscrivo questo per x.encode ('utf-8') si ferma gettando un errore, ma purtroppo quando ho quindi scrivere i dati fuori da qualche altra parte (come latin-1), i segni £ sono tutti diventati confusi. "" "Ovviamente se si scrive testo con codifica UTF-8 su un dispositivo che si aspetta latin1, sarà confuso. Cosa ti aspettavi?

Si dice nella modifica: "" "Ottengo lo stesso errore anche se annullo la riga Latin-1" "". Questo è molto improbabile - molto più probabilmente è che si è verificato un errore leggermente diverso (menzionando il codec latin1 invece del codec ascii) in una linea sorgente diversa (la riga latin1 non commentata invece della riga writerow). Leggere i messaggi di errore aiuta a comprendere attentamente.

Il tuo problema qui è che in generale i tuoi dati NON sono codificabili in latino1; sono pochi dati del mondo reale. Il tuo POUND SIGN è codificabile in latin1, ma non tutti i tuoi dati non ASCII. Il personaggio problematico è U + 2022 BULLET che non è codificabile in latino1.

Ti avrebbe aiutato a ottenere una risposta migliore prima se avessi menzionato in anticipo che stavi lavorando su Mac OS X ... il solito sospetto per una codifica adatta a CSV è cp1252 (Windows), non mac-roman.

+1

"Leggere i messaggi di errore aiuta a capire attentamente." Vero quando il messaggio di errore non è criptico. Forse non nel tuo codice, ma ci sono un sacco di messaggi di errore là fuori che non erano chiaramente destinati a essere letti, almeno non dai terrestri – Davos

5
x = x.decode("ISO-8859-1") 
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa3' in position 0: ordinal not in range(128) 

sguardo da vicino: Hai un Unicode *** Encode *** errore di chiamare il metodo decodifica.

Il motivo di ciò è che decode è destinato alla conversione da una sequenza di byte (str) a un oggetto unicode. Ma, come ha detto John, lo xlrd utilizza già stringhe Unicode, quindi x è già un oggetto unicode.

In questa situazione, Python 2.x presuppone che l'utente indichi per decodificare un oggetto str, in modo che ne sia "utile" crearne uno. Ma per convertire uno unicode in uno str, ha bisogno di una codifica e sceglie ASCII perché è il minimo comune denominatore delle codifiche dei caratteri. Il tuo codice in modo efficace viene interpretato come

x = x.encode('ascii').decode("ISO-8859-1") 

che non riesce a causa x contiene un carattere non ASCII.

Poiché x è già un oggetto , lo decode non è necessario. Tuttavia, ora si incontra il problema che il modulo Python 2.x csv non supporta Unicode. Devi convertire i tuoi dati in oggetti str.

for item in items: 
    item = [x.encode('latin-1') for x in item] 
    cleancsv.writerow(item) 

Questo sarebbe corretto, ad eccezione di avere il carattere (U + 2022 BULLET) nei dati, e latino-1 non può rappresentarlo. Esistono diversi modi per risolvere questo problema:

  • Scrivere x.encode('latin-1', 'ignore') per rimuovere il punto elenco (o altri caratteri non latini-1).
  • Scrivere x.encode('latin-1', 'replace') per sostituire il punto con un punto interrogativo.
  • Sostituire i punti elenco con un carattere Latin-1 come * o ·.
  • Utilizzare una codifica di caratteri che fa contiene tutti i caratteri necessari.

In questi giorni, UTF-8 è ampiamente supportato, quindi non vi sono molti motivi per utilizzare qualsiasi altra codifica per i file di testo.

19

Un modo molto semplice per aggirare il codec "ascii" non può codificare il carattere ... "i problemi con csvwriter è utilizzare invece unicodecsv, una sostituzione drop-in per csvwriter.

Installare unicodecsv con pip e quindi è possibile utilizzarlo in esattamente allo stesso modo, ad esempio:

import unicodecsv 
file = open('users.csv', 'w') 
w = unicodecsv.writer(file) 
for user in User.objects.all().values_list('first_name', 'last_name', 'email', 'last_login'): 
    w.writerow(user) 
0

Lavorando con XLRD, ho in una linea ... xl_data.find (str (CELL_VALUE)) ... che dà l'errore: "Il codec 'ascii' non può codificare il carattere u '\ xdf' in posizione 3: ordinale non nel range (128)". Tutti i suggerimenti nei forum sono stati inutili per le mie parole tedesche. Ma cambiando in: ... xl_data.find (cella.valore) ... non dà errori. Quindi, suppongo che usare stringhe come argomenti in certi comandi con xldr abbia problemi di codifica specifici.

Problemi correlati