Pregunta

Estoy tratando de traducir una hoja de cálculo Excel a CSV usando los módulos XLRD y CSV Python, pero estoy quedarse atascado en problemas de codificación. XLRD produce una salida de Excel en Unicode, y el módulo CSV requiere UTF-8.

I de imagen que esto no tiene nada que ver con el módulo XLRD:. Outputing todo funciona bien a la salida estándar u otras salidas que no requieren una codificación específica

La hoja de cálculo se codifica como UTF-16-LE, de acuerdo con book.encoding

La versión simplificada de lo que estoy haciendo es:

from xlrd import *
import csv
b = open_workbook('file.xls')
s = b.sheet_by_name('Export')
bc = open('file.csv','w')
bcw = csv.writer(bc,csv.excel,b.encoding)
for row in range(s.nrows):
    this_row = []
    for col in range(s.ncols):
        this_row.append(s.cell_value(row,col))
    bcw.writerow(this_row)

Esto produce el error siguiente, alrededor de 740 líneas en:

UnicodeEncodeError: 'ascii' codec can't encode character u'\xed' in position 5: ordinal not in range(128)

El valor se parece quedarse atascado en es "516-777316" - el texto en la hoja de Excel original es "516-7.773.167" (con un 7 en el extremo)

Yo seré el primero en admitir que sólo tengo una vaga sensación de cómo funciona la codificación de caracteres, por lo que la mayor parte de lo que he probado hasta ahora son varias permutaciones torpes de .encode y .decode en el s.cell_value(row,col)

Si alguien pudiera sugerir una solución lo agradecería. - aún mejor si usted podría proporcionar una explicación de lo que no funciona y por qué, para que sea más fácil depurar estos problemas a mí mismo en el futuro

Gracias de antemano!

EDIT:

Gracias por los comentarios hasta ahora.

Cuando this_row.append(s.cell(row,col)) usuario (por ejemplo s.cell en lugar de s.cell_value) todo el documento escribe sin errores.

La salida no es particularmente deseable (text:u'516-7773167'), pero se evita el error a pesar de que los caracteres ofensivos están todavía en la salida.

Esto me hace pensar que el desafío podría estar en XLRD después de todo.

Los pensamientos?

¿Fue útil?

Solución

espero que el valor de retorno cell_value es la cadena Unicode que te está dando problemas (en letra de imprenta su type() confirmar que), en cuyo caso debe ser capaz de resolverlo cambiando esta línea:

this_row.append(s.cell_value(row,col))

a:

this_row.append(s.cell_value(row,col).encode('utf8'))

Si cell_value está regresando varios tipos diferentes, entonces usted necesita para codificar si y sólo si se trata de devolver una cadena Unicode; así que es dividir esta línea en unas pocas líneas:

val = s.cell_value(row, col)
if isinstance(val, unicode):
    val = val.encode('utf8')
this_row.append(val)

Otros consejos

Usted pidió explicaciones, pero algunos de los fenómenos inexplicables sin su ayuda.

(A) Las cadenas en archivos XLS creados por Excel 97 en adelante se codifican en Latin1 si es posible de otra manera en UTF16LE. Cada cadena lleva un revelador indicador que se utiliza. A principios sobresale cadenas codificadas según la "página de códigos" del usuario. En cualquier caso, XLRD produce objetos Unicode . La codificación de archivos es de interés sólo cuando el archivo XLS ha sido creado por el software de 3 ª parte que o bien omite la página de códigos o miente sobre ella. Vea la sección Unicode hasta la parte delantera de la documentación XLRD.

(B) fenómeno inexplicable:

Este código:

bcw = csv.writer(bc,csv.excel,b.encoding)

hace que el siguiente error con Python 2.5, 2.6 y 3.1: TypeError: expected at most 2 arguments, got 3 - esto es sobre lo que cabe esperar dado los documentos en csv.writer; que está esperando un objeto filelike seguido por cualquiera de (1) nada (2) un dialecto o (3) uno o más parámetros de formato. Usted le dio un dialecto, y csv.writer tiene ningún argumento de codificación, por lo splat. ¿Qué versión de Python está usando? ¿O es que no copiar / pegar el script que en realidad se ejecutó?

(C) fenómenos inexplicables alrededor de rastreo y lo que los datos infractor real era:

"the_script.py", line 40, in <module>
this_row.append(str(s.cell_value(row,col)))
UnicodeEncodeError: 'ascii' codec can't encode character u'\xed' in position 5: ordinal not in range(128) 

En primer lugar, es un str () en la línea de código erróneo, que no estaba en el guión simplificado - qué no copiar / pegar el script que en realidad se ejecutó? En cualquier caso, no se debe utilizar str en general - no obtendrá la precisión completa en su flota; simplemente dejar que el módulo csv a convertir.

En segundo lugar, se dice "" "El valor se parece ser cada vez colgó en que es '516-777316' - el texto en la hoja de Excel original es '516 a 7.773.167' (con un 7 en el extremo)" "" --- es difícil imaginar cómo el 7 se pierde fuera de la final. Me gustaría usar algo como esto para saber exactamente cuál era la problemática de datos:

try:
    str_value = str(s.cell_value(row, col))
except:
    print "row=%d col=%d cell_value=%r" % (row, col, s.cell_value(row, col))
    raise

Eso% r te salva de escribir ... cell_value=%s ... repr(s.cell_value(row, col)) la repr () produce una representación inequívoca de sus datos. Aprenderlo. Utilizarlo.

¿Cómo se llega a "516-777316"?

En tercer lugar, el mensaje de error es en realidad la queja de un carácter Unicode U '\ jos' en el offset 5 (es decir, el sexto carácter). U + 00ED es LETRA Latín I con acento agudo, y no es nada de eso en absoluto en "516-7.773.167"

En cuarto lugar, la ubicación del error parece ser un objetivo en movimiento - que ha dicho en un comentario sobre una de las soluciones: "El error se encuentra sobre bcw.writerow." Eh?

(D) ¿Por qué tienes ese mensaje de error (con str ()): str(a_unicode_object) los intentos de convertir el objeto Unicode a un objeto str y en ausencia de cualquier codificación de información utiliza ASCII, pero hay datos que no son ASCII, por lo splat. Tenga en cuenta que su objetivo es producir un archivo CSV codificado en UTF-8, pero su escritura simplificada no menciona utf8 en cualquier lugar.

(E) """ ... s.cell (fila, col)) (egscell en lugar de s.cell_value) todo el documento escribe sin errores La salida no es particularmente deseable (texto:. U'516-7773167' ) "" "

Esto está sucediendo porque el escritor csv está llamando el método __str__ de tu teléfono objeto, y esto produce <type>:<repr(value)> que puede ser útil para la depuración, pero como usted dice no es tan grande en su archivo csv.

solución (F) de Alex Martelli es grande en el que consiguió que va. Sin embargo, usted debe leer la sección sobre la clase celular en los documentos XLRD: tipos de células son de texto, número, booleano, fecha, el error, en blanco y vacío. Si usted tiene fechas, se le va a querer darles formato como fechas no números, por lo que no se puede utilizar isinstance () (y puede que no desee la llamada sobrecarga de la función de todos modos) ... esto es lo que el atributo Cell.ctype y Sheet.cell_type() y métodos Sheet.row_types() son para.

(G) UTF8 no es Unicode. UTF16LE no es Unicode. UTF16 no es Unicode ... y la idea de que las cadenas individuales perderían 2 bytes cada uno en una lista de materiales UTF16 es demasiado descabellado, incluso para MS contemplar: -)

(H) Otras lecturas (aparte de los documentos XLRD):

http://www.joelonsoftware.com/articles/Unicode.html
http://www.amk.ca/python/howto/unicode

Parece que usted tiene 2 problemas.

Hay algo estropeado en esa celda - '7' debe ser codificado como u'x37' Creo que, ya que es dentro del rango ASCII

.

Más importante, sin embargo, el hecho de que usted está recibiendo un mensaje de error que se especifica que el códec ascii no se puede utilizar sugiere que algo anda mal con su codificación en Unicode - que supone que usted está tratando de codificar un 0xed valor que puede' t estar representados en ASCII, pero dijo que está tratando de representarlo en unicode.

No soy lo suficientemente inteligente como para trabajar en lo particular, la línea es la causa del problema - si edita su pregunta a decirme qué línea es la causa de que el mensaje de error que podría ser capaz de ayudar a un poco más (que supongo que es ya sea this_row.append(s.cell_value(row,col)) o bcw.writerow(this_row), pero agradecería que confirma).

Parece que hay dos posibilidades. Una de ellas es que no ha tal vez abierto el archivo de salida correctamente:

"Si csvfile es un objeto de archivo, que debe abrirse con la bandera‘b’en plataformas para las que hace la diferencia." ( http://docs.python.org/library/csv.html#module -csv )

Si ese no es el problema, entonces otra opción para usted es utilizar codecs.EncodedFile (archivo, entrada [, la salida [errores]]) como un envoltorio para dar salida a su .csv:

http://docs.python.org/library/codecs.html # module-codecs

Esto le permitirá tener el filtro objeto de archivo de UTF16 entrante a UTF8. Si bien ambos son técnicamente "Unicode", la forma en que codifican es muy diferente.

Algo como esto:

rbc = open('file.csv','w')
bc = codecs.EncodedFile(rbc, "UTF16", "UTF8")
bcw = csv.writer(bc,csv.excel)

puede resolver el problema para usted, asumiendo entendí el problema de la derecha, y suponiendo que el error es lanzada al escribir en el archivo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top