Pergunta

Eu estou tentando traduzir uma planilha Excel para CSV usando os xlrd e CSV módulos Python, mas estou ficando pendurado na codificação de questões. Xlrd produz saída do Excel em Unicode, e o módulo CSV requer UTF-8.

I imaginando que isso não tem nada a ver com o módulo xlrd:. Tudo funciona outputing fina para stdout ou outras saídas, que não exigem uma codificação específica

A folha de cálculo é codificado como UTF-16-LE, de acordo com book.encoding

A versão simplificada do que estou fazendo é:

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)

Isso produz o seguinte erro, cerca de 740 linhas em:

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

O valor é parece estar ficando pendurado em é "516-777316" - o texto na folha de Excel original é "516-7773167" (com um 7 no final)

Eu serei o primeiro a admitir que eu só tenho uma vaga sensação de como funciona a codificação de caracteres, então a maioria do que eu tentei até agora são várias permutações desajeitados de .encode e .decode no s.cell_value(row,col)

Se alguém poderia sugerir uma solução eu apreciaria -. Ainda melhor se você poderia fornecer uma explicação do que não está funcionando e por isso, para que eu possa mais facilmente depurar esses problemas me no futuro

Agradecemos antecipadamente!

EDIT:

Obrigado pelos comentários até agora.

Quando eu this_row.append(s.cell(row,col)) usuário (por exemplo s.cell vez de s.cell_value) toda as gravações documento sem erros.

A saída não é particularmente desejável (text:u'516-7773167'), mas evita o erro mesmo que os personagens ofender ainda estão na saída.

Isso me faz pensar que o desafio pode estar em xlrd depois de tudo.

Os pensamentos?

Foi útil?

Solução

Espero que o valor cell_value retorno é a seqüência de caracteres Unicode que está lhe dando problemas (em letra de sua type() para confirmar isso), caso em que você deve ser capaz de resolvê-lo, alterando esta linha um:

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

para:

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

Se cell_value é retornar vários tipos diferentes, então você precisa codificar se e somente se ele está retornando uma seqüência de caracteres Unicode; assim você iria dividir essa linha em poucas linhas:

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

Outras dicas

Você pediu explicações, mas alguns dos fenômenos são inexplicáveis ??sem a sua ajuda.

arquivos

(A) Cordas em XLS criados pelo Excel 97 em diante são codificados em Latin1 se possível de outra forma em UTF16LE. Cada corda carrega um revelador bandeira que foi usado. Excels anteriores codificado seqüências de acordo com a "página de códigos" do usuário. Em qualquer caso, xlrd produz objetos unicode . A codificação do arquivo é de interesse somente quando o arquivo XLS foi criado por software 3o partido que ou omite a página de códigos ou mentiras sobre ele. Consulte a seção Unicode-se a frente dos docs xlrd.

(B) fenômeno inexplicável:

Este código:

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

faz com que o seguinte erro com o Python 2.5, 2.6 e 3.1: TypeError: expected at most 2 arguments, got 3 - isto é sobre o que eu esperaria dada a documentação sobre csv.writer; ele está esperando um objecto filelike seguido por (1) nada (2) um dialeto ou (3) um ou mais parâmetros de formatação. Você deu um dialeto, e csv.writer não tem codificação argumento, então splat. Qual versão do Python você está usando? Ou será que você não copiar / colar o script que você realmente funcionou?

(C) inexplicável fenômenos em torno de rastreamento e quais foram os dados de ofensa reais:

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

Em primeiro lugar, há uma str () na linha de código incorreto, que não estava no roteiro simplificado - se você não copiar / colar o script que você realmente funcionou? Em qualquer caso, você não deve usar str em geral - você não vai obter a precisão total em seus carros alegóricos; apenas deixá-los o módulo csv convertido.

Em segundo lugar, você diz "" "O valor é parece estar ficando pendurado em é '516-777316' - o texto na folha de Excel original é '516-7773167' (com um 7 no final)" "" --- é difícil imaginar como o 7 se perde fora da final. Eu usaria algo assim para descobrir exatamente o que era o de dados problemático:

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

Isso% r evita que você cell_value=%s ... repr(s.cell_value(row, col)) digitação ... o repr () produz uma representação inequívoca de seus dados. Aprenda. Usá-lo.

Como você chegou a "516-777316"?

Em terceiro lugar, a mensagem de erro está realmente reclamando sobre um personagem unicode u '\ xa' no deslocamento 5 (ou seja, o sexto caractere). U + 00ED é a minúsculo I COM aguda, e não há nada assim em tudo na "516-7773167"

Em quarto lugar, a localização de erro parece ser um alvo em movimento - você disse em um comentário sobre uma das soluções: "O erro está em bcw.writerow." Huh?

(D) Por que você tem essa mensagem de erro (com str ()): tentativas str(a_unicode_object) para converter o objeto unicode para um objeto str e na ausência de qualquer codificação usa informações ascii, mas você tem dados não-ASCII, de forma splat. Note-se que o seu objetivo é produzir um arquivo CSV codificados em UTF-8, mas o seu roteiro simplificado não menciona utf8 em qualquer lugar.

(E) """ ... s.cell (linha, col)) (egscell vez de s.cell_value) inteiras as gravações documento sem erros a saída não é particularmente desejável (texto:. U'516-7773167' ) "" "

Isso está acontecendo porque o escritor CSV é chamar o método __str__ de seu celular objeto, e isso produz <type>:<repr(value)> que pode ser útil para depuração, mas não como você diz tão grande em seu arquivo CSV.

solução (F) Alex Martelli é grande na medida em que tenho você vai. No entanto, você deve ler a seção sobre a classe celular nos docs xlrd: tipos de células são texto, número, booleano, data, erro, branco e vazio. Se você tem datas, você vai querer formatar-los como datas não números, então você não pode usar isinstance () (e você não pode querer a chamada de função em cima de qualquer maneira) ... isto é o que o atributo Cell.ctype e Sheet.cell_type() e métodos Sheet.row_types() são para.

(G) UTF8 não é Unicode. UTF16LE não é Unicode. UTF16 não é Unicode ... ea ideia de que strings individuais iria perder 2 bytes cada um em uma UTF16 BOM é demasiado absurdo para MS até mesmo para contemplar: -)

(H) Leitura adicional (para além dos documentos xlrd):

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

Parece que temos 2 problemas.

Há algo asneira em que a célula -. '7' deve ser codificado como u'x37' Eu acho que, uma vez que é dentro do ASCII-range

Mais importante, porém, o fato de que você está recebendo uma mensagem de erro especificando que o codec ascii não pode ser usado sugere errada de algo com a sua codificação em unicode - ele pensa que você está tentando codificar um valor 0xed que pode' t ser representados em ASCII, mas você disse que está tentando representá-lo em unicode.

Eu sou o suficiente para não inteligente para descobrir o que determinada linha está causando o problema - se você editar a sua pergunta para me dizer qual linha está causando essa mensagem de erro que eu poderia ser capaz de ajudar um pouco mais (eu acho que é tanto this_row.append(s.cell_value(row,col)) ou bcw.writerow(this_row), mas gostaria que você confirmar).

Parece haver duas possibilidades. Uma delas é que você não tenha, talvez, abriu o arquivo de saída corretamente:

"Se csvfile é um objeto de arquivo, ele deve ser aberto com o sinalizador‘b’em plataformas onde isso faz a diferença." ( http://docs.python.org/library/csv.html#module -CSV )

Se isso não é o problema, então outra opção para você é usar codecs.EncodedFile (arquivo, input [, saída [, erros]]) como um wrapper para a saída de seu .csv:

http://docs.python.org/library/codecs.html # módulo-codecs

Isto irá permitir que você tenha o filtro objeto de arquivo de UTF16 de entrada para UTF8. Enquanto ambos são tecnicamente "unicode", a forma como eles codificam é muito diferente.

Algo parecido com isto:

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

pode resolver o problema para você, supondo que eu entendi o direito problema, e assumindo que o erro é lançado ao escrever para o arquivo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top