2010-08-27 16 views
22

Tengo una hoja de cálculo de Excel que estoy leyendo que contiene algunos signos de £.UnicodeEncodeError: el códec 'ascii' no puede codificar el carácter u ' xa3'

cuando trato de leerlo en el uso del módulo de XLRD, me sale el siguiente error:

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) 

Si vuelvo a escribir esto a x.encode ('UTF-8') que deje de tirar un error, pero desafortunadamente cuando escribo los datos en otro lugar (como latin-1), los signos de £ se vuelven confusos.

¿Cómo puedo solucionar esto y leer los signos £ correctamente?

--- --- ACTUALIZACIÓN

Una especie lectores han sugerido que no necesito de decodificarlo en absoluto, o que sólo puede codificar a Latin-1 cuando necesito. El problema con esto es que necesito escribir los datos en un archivo CSV eventualmente, y parece que se opone a las cadenas sin formato.

Si no codificar o decodificar los datos en absoluto, entonces esto sucede (después de haber añadido la cadena en una matriz llamados elementos):

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) 

me sale el mismo error incluso si eliminar el comentario de la línea Latin-1.

+0

¿Está '.decode'-ing dos veces? – katrielalex

+0

No lo creo. Sin embargo, la línea anterior es x = table.cell_value (row, col), del módulo xlrd, ¿quizás eso está haciendo algo gracioso? – AP257

Respuesta

9

el fragmento de código dice x.decode, pero que está recibiendo un codificar error - lo que significa x es Unicode ya, así, a "decodificar" que, primero debe ser convertida en una cadena de bytes (y ahí es donde el códec predeterminado ansi aparece y falla). En su texto, usted dice "si reescribo ot a x. codifique" ... lo que parece implicar que haga sepa que x es Unicode.

Entonces, ¿qué es lo que está haciendo - y qué es lo que significa estar haciendo - que codifica una x Unicode para obtener una cadena codificada de bytes, o decodificar una cadena de bytes en un objeto Unicode?

Me parece lamentable que se puede llamar encode en una cadena de bytes, y decode en un objeto Unicode, porque encuentro que parece conducir al usuario a nada más que confusión ... pero al menos en este caso parece que gestionar para propagar la confusión (al menos para mí ;-).

Si, como parece, x es Unicode, entonces nunca quieren "decodificar" ella - es posible que desee codificar que para obtener una cadena de bytes con un cierto códec, por ejemplo, latin-1, si eso es lo que necesita algún tipo de fines de E/S (para su propio uso interno programa que recomiendo quedarse con Unicode todo el tiempo - sólo se envío/recepción, siempre y cuando sea absolutamente necesidad o reciben, cadenas de bytes codificados para fines de entrada/salida).

+1

Gracias. Supongo que es unicode, pero necesito codificarlo para que lo escriba en un archivo CSV. Cuando intento codificarlo en latin-1, aparece otro error. Por favor, mira mi actualización anterior ... – AP257

+1

Lo descubrí - la línea que necesitaba antes de escribir en CSV era item = [x.encode ('mac_roman') para x en el elemento]. Aceptar esta respuesta porque me ayudó a descubrir qué estaba pasando, gracias. – AP257

+0

@ alex-martelli Me gustaría obtener su opinión sobre [esta pregunta] (http://stackoverflow.com/questions/23013236/how-to-encode-xml-into-esri-shapefiles-using-python). – JJD

2

xlrd obras con Unicode, por lo que la cadena que se obtiene es una cadena Unicode. El signo £ tiene un punto de código U + 00A3, por lo que la representación de dicha cadena debe ser u'\xa3'. Esto ha sido leído correctamente; es la cadena con la que debería trabajar a lo largo de su programa.

Cuando escribe esta cadena (abstracta, Unicode) en alguna parte, debe elegir una codificación.En ese punto, debe .encode en esa codificación, por ejemplo 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

por favor, consulte mi actualización anterior: me aparece un error cuando intento codificarlo ... – AP257

10

Por lo que vale la pena: yo soy el autor de xlrd.

¿xlrd produce unicode?
Opción 1: Lea la sección Unicode en la parte inferior de la primera pantalla de xlrd doc: Este módulo presenta todas las cadenas de texto como objetos Unicode de Python.
Opción 2: print type(text), repr(text)

se dice "" "Si vuelvo a escribir esto a x.encode ('UTF-8') que se detenga lanzando un error, pero por desgracia, cuando se escriba los datos en otro lugar (como se latin-1), los signos de £ se han distorsionado. "" "Por supuesto, si escribes texto con codificación UTF-8 en un dispositivo que espera Latin1, se distorsionará. ¿Qué esperabas?

Usted dice en su edición: "" "Me sale el mismo error incluso si elimino el comentario de la línea Latin-1" "". Esto es muy improbable: es mucho más probable que tenga un error ligeramente diferente (mencionando el códec latin1 en lugar del códec ascii) en una línea de origen diferente (la línea latina1 no commentada en lugar de la línea writerow). Leer los mensajes de error ayuda a comprender.

Su problema aquí es que, en general, sus datos NO son codificables en latin1; muy pocos datos del mundo real. Su SEÑAL DE LIBRA es codificable en latin1, pero no todos sus datos no ASCII. El personaje problemático es U + 2022 BULLET que no es codificable en latin1.

Le hubiera ayudado a obtener una mejor respuesta antes si hubiera mencionado de antemano que estaba trabajando en Mac OS X ... el sospechoso habitual para una codificación adecuada para CSV es cp1252 (Windows), no mac-roman.

+1

"Leer los mensajes de error ayuda a comprender". Es cierto cuando el mensaje de error no es críptico. Quizás no en su código, pero hay muchos mensajes de error que claramente nunca fueron destinados a ser leídos, al menos no por los terrícolas – 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) 

Mira de cerca: Usted tiene un Unicode *** *** Codificar error llamando al métododecodificación.

La razón para esto es que decode está destinado a convertir de una secuencia de bytes (str) a un objeto unicode. Pero, como dijo John, xlrd ya usa cadenas Unicode, por lo que x ya es un objeto unicode.

En esta situación, Python 2.x asume que significó para decodificar un objeto str, por lo que "de manera útil" crea uno para usted. Pero para convertir un unicode en un str, necesita una codificación, y elige ASCII porque es el denominador común más bajo de las codificaciones de caracteres. Su código efectivamente se interpreta como

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

no lo consigue porque x contiene un carácter no ASCII.

Dado que x ya es un objeto unicode, el decode es innecesario. Sin embargo, ahora se encuentra con el problema de que el módulo Python 2.x csv no es compatible con Unicode. Tienes que convertir tus datos a objetos str.

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

Esto sería correcto, excepto que usted tiene el carácter (U + 2022 BALA) en sus datos, y América-1 no puede representarla. Hay varias formas de evitar este problema:

  • Escribir x.encode('latin-1', 'ignore') para retirar la bala (u otros Latin-1 que no son caracteres).
  • Escriba x.encode('latin-1', 'replace') para reemplazar la viñeta con un signo de interrogación.
  • Reemplace las viñetas con un carácter Latin-1 como * o ·.
  • Utilice una codificación de caracteres que tiene contiene todos los caracteres que necesita.

En la actualidad, UTF-8 es ampliamente compatible, por lo que hay pocas razones para utilizar cualquier otra codificación para archivos de texto.

19

Una manera muy fácil de resolver todos los problemas del codec "ascii" no puede codificar el carácter ... "con csvwriter es utilizar unicodecsv, un reemplazo directo para csvwriter.

Instalar unicodecsv con la pipa y luego se puede usar de la misma manera exacta, por ejemplo:

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

Trabajar con XLRD, tengo en una línea ... xl_data.find (str (CELL_VALUE)) ... que da el error: "el códec 'ascii' no puede codificar el carácter u '\ xdf' en la posición 3: el ordinal no está en el rango (128)". Todas las sugerencias en los foros han sido inútiles para mis palabras alemanas. Pero cambiando a: ... xl_data.find (cell.value) ... no da error. Entonces, supongo que usar cadenas como argumentos en ciertos comandos con xldr tiene problemas específicos de codificación.

Cuestiones relacionadas