xldate_as_datetime xldate library exportar python unicode encoding csv xlrd

xldate - Unicode a UTF8 para archivos CSV-Python a través de xlrd



python xls (4)

Espero que el valor de retorno de valor de la cell_value sea ​​la cadena Unicode que le está dando problemas (imprima su type() para confirmar eso), en cuyo caso debería poder 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á devolviendo varios tipos diferentes, entonces necesita codificar si y solo si está devolviendo una cadena Unicode; entonces dividirías 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)

Estoy tratando de traducir una hoja de cálculo de Excel a CSV utilizando los módulos Python xlrd y csv, pero me estoy quedando colgado de los problemas de codificación. Xlrd produce resultados de Excel en Unicode, y el módulo CSV requiere UTF-8.

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

La hoja de trabajo está codificada 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 siguiente error, alrededor de 740 líneas en:

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

Parece que el valor se está quedando colgado en "516-777316"; el texto en la hoja original de Excel es "516-7773167" (con un 7 en el extremo)

Seré el primero en admitir que solo tengo un vago sentido de cómo funciona la codificación de caracteres, por lo que la mayoría de lo que he intentado hasta ahora son varias permutaciones de .encode y .decode en el s.cell_value(row,col)

Si alguien pudiera sugerir una solución, le agradecería, incluso mejor si pudiera proporcionar una explicación de lo que no funciona y por qué, para poder depurar estos problemas más fácilmente en el futuro.

¡Gracias por adelantado!

EDITAR:

Gracias por los comentarios hasta ahora.

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

La salida no es particularmente deseable ( text:u''516-7773167'' ), pero evita el error aunque los caracteres ofensivos aún estén en la salida.

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

¿Pensamientos?


Parece que hay dos posibilidades. Una es que quizás no haya abierto el archivo de salida correctamente:

"Si csvfile es un objeto de archivo, debe abrirse con la bandera ''b'' en las plataformas donde eso haga una diferencia". ( http://docs.python.org/library/csv.html#module-csv )

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

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

Esto le permitirá tener el filtro de objeto de archivo de UTF16 entrante a UTF8. Si bien ambos son técnicamente "Unicode", la forma en que se 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 por usted, asumiendo que entendí bien el problema, y ​​asumiendo que el error se produce al escribir en el archivo.


Parece que tienes 2 problemas.

Hay algo estropeado en esa celda: ''7'' debería codificarse como u''x37 '', creo, ya que está dentro del rango ASCII.

Sin embargo, lo más importante es que el hecho de que aparezca un mensaje de error que especifique que no se puede usar el códec ascii sugiere que algo está mal con su codificación en Unicode. Piensa que está intentando codificar un valor 0xed que no se puede representar. en ASCII, pero usted dijo que está tratando de representarlo en Unicode.

No soy lo suficientemente inteligente como para averiguar qué línea en particular está causando el problema. Si edita su pregunta para decirme qué línea está causando ese mensaje de error, es posible que pueda ayudar un poco más (supongo que es this_row.append(s.cell_value(row,col)) o bcw.writerow(this_row) , pero le agradecería que lo confirme.


Pediste explicaciones, pero algunos de los fenómenos son inexplicables sin tu ayuda.

(A) Las cadenas en los archivos XLS creados por Excel 97 en adelante se codifican en Latin1, si es posible de lo contrario en UTF16LE. Cada cadena lleva una bandera que dice que se utilizó. Excels anterior codificó cadenas según la "página de códigos" del usuario. En cualquier caso, xlrd produce objetos Unicode . La codificación del archivo es de interés solo cuando el archivo XLS ha sido creado por un software de terceros que omite la página de códigos o miente al respecto. Consulte la sección Unicode en la parte frontal de los documentos xlrd.

(B) Fenómeno inexplicable:

Este codigo

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

causa 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 esperaría dada la documentación en csv.writer; está esperando un objeto similar a un archivo seguido de (1) nada (2) un dialecto o (3) uno o más parámetros de formato. Le diste un dialecto, y csv.writer no tiene ningún argumento de codificación, por lo tanto, splat. ¿Qué versión de Python estás usando? ¿O no copió / pegó el guión que realmente ejecutó?

(C) Fenómenos inexplicables en torno al rastreo y cuáles fueron los datos ofensivos reales:

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

PRIMERO, hay un str () en la línea de código ofensiva que no estaba en el script simplificado. ¿No copió / pegó el script que realmente ejecutó? En cualquier caso, no debe usar str en general, no obtendrá la precisión total en sus flotadores; solo deja que el modulo csv los convierta.

SEGUNDO, usted dice "" "El valor que parece estar quedando colgado es" 516-777316 "- el texto en la hoja original de Excel es" 516-7773167 "(con un 7 en el extremo)" "" - - Es difícil imaginar cómo se pierden los 7 del final. Usaría algo como esto para averiguar exactamente cuáles eran los datos problemáticos:

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

Ese% r evita que escriba cell_value=%s ... repr(s.cell_value(row, col)) ... repr () produce una representación inequívoca de sus datos. Aprenderlo. Utilízalo

¿Cómo llegaste a "516-777316"?

TERCERAMENTE, el mensaje de error en realidad se queja sobre un carácter Unicode u ''/ xed'' en el desplazamiento 5 (es decir, el sexto carácter). U + 00ED es LETRA PEQUEÑA LATINA CON AGUDA, y no hay nada de eso en "516-7773167"

CUARTO, la ubicación del error parece ser un objetivo móvil, dijo en un comentario sobre una de las soluciones: "El error está en bcw.writerow". Eh

(D) Por qué recibió ese mensaje de error (con str ()): str(a_unicode_object) intenta convertir el objeto Unicode en un objeto Str y, en ausencia de cualquier información de codificación, utiliza ascii, pero tiene datos que no son ASCII, por lo que splat. Tenga en cuenta que su objeto es producir un archivo csv codificado en utf8, pero su script simplificado no menciona utf8 en ninguna parte.

(E) "" "... s.cell (row, col)) (por ejemplo, scell en lugar de s.cell_value) todo el documento escribe sin errores. La salida no es particularmente deseable (texto: u''516-7773167 '') ""

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

(F) La solución de Alex Martelli es grandiosa porque te puso en marcha. Sin embargo, debe leer la sección sobre la clase de celda en los documentos xlrd: los tipos de celda son texto, número, booleano, fecha, error, en blanco y vacío. Si tiene fechas, querrá formatearlas como fechas, no como números, por lo que no puede usar isinstance () (y es posible que no desee la sobrecarga de llamadas a la función) ... esto es lo que el atributo Cell.ctype y los Sheet.cell_type() y 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 desperdiciarían 2 bytes cada una en una lista de materiales UTF16 es demasiado absurda para que incluso MS la contemple :-)

(H) Lecturas adicionales (aparte de los documentos xlrd):

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