Domanda

Sto cercando di tradurre un foglio di calcolo Excel in formato CSV utilizzando i XLRD e csv moduli Python, ma sono sempre appeso su problemi di codifica. XLRD produce output da Excel in Unicode, e il modulo CSV richiede UTF-8.

di imaging ho che questo non ha nulla a che fare con il modulo XLRD:. Tutto funziona bene per outputing stdout o altre uscite che non richiedono una codifica specifica

Il foglio di lavoro è codificato come UTF-16-LE, secondo book.encoding

La versione semplificata di quello che sto facendo è:

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)

Questo produce il seguente errore, circa 740 linee in:

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

Il valore è sembra essere sempre appeso su è "516-777.316" - il testo nel foglio di Excel originale è "516-7.773.167" (con un 7 alla fine)

Sarò il primo ad ammettere che ho solo un vago senso di come funziona la codifica dei caratteri, quindi la maggior parte di quello che ho provato finora sono varie permutazioni maldestri di .encode e .decode sul s.cell_value(row,col)

Se qualcuno potesse suggerire una soluzione sarei grato -. Ancora meglio se si potrebbe fornire una spiegazione di ciò che non funziona e perché, in modo che possa più facilmente eseguire il debug di questi problemi io in futuro

Grazie in anticipo!

Modifica

Grazie per i commenti finora.

Quando ho utente this_row.append(s.cell(row,col)) (ad esempio s.cell anziché s.cell_value) l'intero documento, scrive senza errori.

L'uscita non è particolarmente desiderabile (text:u'516-7773167'), ma evita l'errore anche se i caratteri problematici sono ancora in uscita.

Questo mi fa pensare che la sfida potrebbe essere in XLRD dopo tutto.

Pensieri?

È stato utile?

Soluzione

Mi aspetto che il valore di ritorno cell_value è la stringa unicode che si sta dando problemi (in stampatello la sua type() confermare che), nel qual caso si dovrebbe essere in grado di risolverlo modificando questa riga:

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

a:

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

Se cell_value sta tornando più tipi diversi, allora avete bisogno di codificare se e solo se è restituendo una stringa unicode; così si potrebbe dividere questa linea in poche righe:

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

Altri suggerimenti

Avete chiesto spiegazioni, ma alcuni dei fenomeni inspiegabili senza il vostro aiuto.

(A) stringhe in file XLS creati da Excel 97 in poi sono codificati in Latin1, se possibile, tuttavia in UTF16LE. Ogni stringa porta un racconto bandiera che è stato utilizzato. In precedenza eccelle codificato le stringhe in base alla "tabella codici" dell'utente. In ogni caso, XLRD produce oggetti Unicode . La codifica del file è di interesse solo quando il file XLS è stato creato da un software 3rd party che o omette la tabella di codici o si trova su di esso. Vedere la sezione Unicode la parte anteriore dei documenti XLRD.

(B) fenomeno inspiegabile:

Il codice:

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

provoca il seguente errore con Python 2.5, 2.6 e 3.1: TypeError: expected at most 2 arguments, got 3 - si tratta di quello che ci si aspetterebbe data la documentazione su csv.writer; si aspetta un oggetto filelike seguito da (1) nulla (2) un dialetto o (3) uno o più parametri di formattazione. Si diede un dialetto, e csv.writer ha nessun argomento di codifica, così splat. Quale versione di Python stai usando? Oppure non hai copia / incolla lo script che in realtà eseguito?

(C) fenomeni inspiegabili intorno traceback e quali i dati effettivi incriminata 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) 

primo luogo, c'è una str () nella riga di codice incriminata che non era nel copione semplificato - non mi hai copia / incolla lo script che effettivamente eseguito? In ogni caso, non si dovrebbe usare str in generale - non sarà possibile ottenere la massima precisione sui tuoi carri; basta lasciare che il modulo csv convertirli.

secondo luogo, si dice "" "Il valore è sembra essere sempre appeso su è '516-777.316' - il testo nel foglio di Excel originale è '516-7.773.167' (con un 7 alla fine)" "" --- è difficile immaginare come la 7 si perde fuori alla fine. Mi piacerebbe usare qualcosa di simile per scoprire esattamente ciò che i dati problematico era:

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

Che% r si evita di digitare cell_value=%s ... repr(s.cell_value(row, col)) ... il repr () produce una rappresentazione univoca dei dati. Imparalo. Usalo.

Come sei arrivato a "516-777.316"?

In terzo luogo il messaggio di errore è effettivamente lamenta un carattere Unicode U '\ sse' all'offset 5 (vale a dire il sesto carattere). U + 00ED è latino: lettera I con accento acuto, e non c'è niente di simile a tutti in "516-7.773.167"

In quarto luogo, la posizione errore sembra essere un bersaglio in movimento - che ha detto in un commento su una delle soluzioni: "L'errore è in bcw.writerow." Eh?

(D) Perché hai quel messaggio di errore (con str ()): str(a_unicode_object) tenta di convertire l'oggetto unicode a un oggetto str e in assenza di qualsiasi codifica di informazioni utilizza ASCII, ma si dispone di dati non-ASCII, in modo da splat. Si noti che l'oggetto è quello di produrre un file CSV codificato in utf8, ma lo script semplificato non menziona utf8 da nessuna parte.

(E) """ ... s.cell (riga, col)) (egscell anziché s.cell_value) dell'intero documento scrive senza errori L'uscita non è particolarmente auspicabile (testo:. U'516-7773167' ) "" "

Quello che sta succedendo perché lo scrittore csv sta chiamando il metodo __str__ del tuo cellulare oggetto, e questo produce <type>:<repr(value)> che può essere utile per il debugging, ma come dici tu non è così grande nel file CSV.

La soluzione di (F) Alex Martelli è grande in quanto ha ottenuto in corso. Tuttavia si dovrebbe leggere la sezione sulla classe cella nella documentazione XLRD: tipi di cellule sono testo, numero, booleano, la data, l'errore, vuoto e vuoto. Se si dispone di date, si sta andando a voler formattare loro come date non numeri, quindi non è possibile utilizzare isinstance () (e non si può decidere la chiamata in testa funzione in ogni caso) ... questo è ciò che l'attributo Cell.ctype e Sheet.cell_type() e metodi Sheet.row_types() sono per.

(G) UTF8 non è Unicode. UTF16LE non è Unicode. UTF16 non è Unicode ... e l'idea che singole stringhe sarebbero sprecate 2 byte ciascuno su un UTF16 BOM è troppo assurda anche per gli Stati membri a contemplare: -)

(H) Ulteriori letture (a parte la documentazione XLRD):

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

Sembra che tu hai 2 problemi.

C'è qualcosa avvitato in quella cella - '7' dovrebbe essere codificato come u'x37' Credo che, dal momento che è all'interno della ASCII-range

.

Ancora più importante, però, il fatto che stai ricevendo un messaggio di errore che specifica che il codec ascii non può essere utilizzato suggerisce qualcosa di sbagliato con la codifica in unicode - pensa si sta cercando di codificare un 0xed valore che puo' t essere rappresentato in ASCII, ma lei ha detto che sta cercando di rappresentarlo in unicode.

Io non sono abbastanza intelligente per capire cosa particolare linea è la causa del problema - se si modifica la tua domanda di dirmi quale linea sta causando quel messaggio di errore potrei essere in grado di aiutare un po 'di più (credo che sia sia this_row.append(s.cell_value(row,col)) o bcw.writerow(this_row), ma gradirebbe si conferma).

Sembra che ci siano due possibilità. Uno è che non si è forse aperto il file di output in modo corretto:

"Se csvfile è un oggetto file, deve essere aperto con il flag‘b’su piattaforme in cui questo fa la differenza." ( http://docs.python.org/library/csv.html#module -CSV )

Se questo non è il problema, allora un'altra opzione per voi è quello di utilizzare codecs.EncodedFile (file, ingresso [, uscita [, errors]]) come un wrapper per l'output del .csv:

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

Questo vi permetterà di avere il filtro oggetto file da UTF16 in entrata a UTF8. Mentre entrambi sono tecnicamente "unicode", il modo in cui codificano è molto diversa.

Qualcosa di simile a questo:

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

può risolvere il problema per voi, assumendo che ho capito il problema a destra, e assumendo che l'errore viene generato durante la scrittura al file.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top