Question

Je suis en train de traduire une feuille de calcul Excel au format CSV en utilisant les modules de xlrd et csv Python, mais je enferrons sur les questions de codage. Xlrd produit une sortie à partir d'Excel en Unicode, et le module CSV nécessite UTF-8.

imagerie I que cela n'a rien à voir avec le module xlrd. Tout fonctionne bien outputing à stdout ou d'autres sorties qui ne nécessitent pas un codage spécifique

La feuille de calcul est codé comme UTF-16-LE, selon book.encoding

La version simplifiée de ce que je fais est:

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)

Ceci produit l'erreur suivante, environ 740 lignes:

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

La valeur est semble enferrons sur est « 516-777316 » - le texte dans la feuille Excel d'origine est « 516-7773167 » (avec 7 à la fin)

Je serai le premier à admettre que je n'ai qu'un vague sentiment du fonctionnement de codage de caractères, donc la plupart de ce que j'ai essayé jusqu'à présent sont différentes permutations tâtonnants de .encode et .decode sur le s.cell_value(row,col)

Si quelqu'un pourrait proposer une solution, je vous serais reconnaissant -. Encore mieux si vous pouvez fournir une explication de ce qui ne fonctionne pas et pourquoi, afin que je puisse déboguer plus facilement ces problèmes moi-même dans l'avenir

Merci d'avance!

EDIT:

Merci pour les commentaires à ce jour.

Quand je this_row.append(s.cell(row,col)) utilisateur (par exemple s.cell au lieu de s.cell_value) l'ensemble du document écrit sans erreurs.

La sortie est pas particulièrement souhaitable (text:u'516-7773167'), mais elle évite l'erreur même si les caractères incriminés sont encore dans la sortie.

Cela me fait penser que le défi pourrait être xlrd après tout.

Pensées

Était-ce utile?

La solution

Je me attends à la valeur de retour de cell_value est la chaîne unicode qui est en vous donnant des problèmes (s'il vous plaît imprimer son type() confirmer que), dans ce cas, vous devriez être en mesure de le résoudre en changeant cette seule ligne:

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

à:

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

Si cell_value retourne plusieurs types différents, alors vous devez encoder si et seulement si elle est de retour d'une chaîne unicode; afin de diviser cette tu ligne en quelques lignes:

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

Autres conseils

Vous avez demandé des explications, mais quelques-uns des phénomènes inexplicables sans votre aide.

(A) Les chaînes dans les fichiers XLS créés par Excel 97 partir sont encodées dans Latin1, si possible, sinon dans UTF16LE. Chaque chaîne porte un révélateur de drapeau qui a été utilisé. Plus tôt Excelle chaînes codées selon la « page de code » de l'utilisateur. Dans tous les cas, xlrd produit des objets unicode . L'encodage de fichiers est d'intérêt que lorsque le fichier XLS a été créé par le logiciel 3ème partie qui soit omet le codepage ou est à ce sujet. Voir la section Unicode l'avant des xlrd docs.

(B) phénomène inexpliqué:

Ce code:

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

provoque l'erreur suivante avec Python 2.5, 2.6 et 3.1: TypeError: expected at most 2 arguments, got 3 - c'est ce que je vous attendriez donné la documentation sur csv.writer; il attend un objet suivi soit par type fichier (1) rien (2) un dialecte ou (3) un ou plusieurs paramètres de formatage. Vous lui a donné un dialecte, et csv.writer n'a pas d'argument de codage, de sorte floc. Quelle version de Python utilisez-vous? Ou avez-vous pas copier / coller le script que vous avez réellement exécuté?

(C) des phénomènes inexpliqués autour retraçage et ce que les données de la délinquance réelle était:

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

ABORD, il y a une str () dans la ligne de code incriminé qui n'a pas été dans le script simplifié - vous ne l'avez pas copier / coller le script que vous avez réellement exécuté? Dans tous les cas, vous ne devriez pas utiliser str en général - vous ne serez pas la pleine précision sur vos flotteurs; il suffit de laisser le module csv les convertir.

SECOND, vous dites « » « La valeur est semble enferrons sur est « 516-777316 » - le texte dans la feuille Excel d'origine est « 516-7773167 »(avec un 7 sur la fin) » « » --- il est difficile d'imaginer comment le 7 se perd à l'extrémité. J'utilise quelque chose comme ça pour savoir exactement ce que les données problématiques était:

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

Ce r% vous évite de taper cell_value=%s ... repr(s.cell_value(row, col)) ... la repr () produit une représentation sans ambiguïté de vos données. Apprend le. Utilisez-le.

Comment êtes-vous arrivé à "516-777316"?

Troisièmement, le message d'erreur se fait auprès d'un caractère unicode u « \ xe » à décalage 5 (à savoir le sixième caractère). U + 00ED est LETTRE MINUSCULE LATINE I AIGU, et il n'y a rien du tout comme ça dans « 516-7773167 »

quatrièmement, l'emplacement d'erreur semble être une cible en mouvement - vous avez dit dans un commentaire sur l'une des solutions: « L'erreur est sur bcw.writerow. » Huh?

(D) Pourquoi vous avez obtenu ce message d'erreur (avec str ()): str(a_unicode_object) tente de convertir l'objet unicode à un objet str et en l'absence de toute information de codage utilise ascii, mais vous avez des données non-ascii, donc floc. Notez que votre objet est de produire un fichier csv codé en UTF8, mais votre script simplifié ne mentionne pas UTF8 nulle part.

(E) "" » ... s.cell (ligne, colonne)) (egscell au lieu de s.cell_value) l'ensemble du document écrit sans erreur La sortie est pas particulièrement souhaitable (texte:. U'516-7773167' ) "" "

Cela se produit parce que l'écrivain csv appelle la méthode __str__ de votre objet Cell, et ce produit <type>:<repr(value)> qui peut être utile pour le débogage, mais comme vous le dites pas si grand dans votre fichier csv.

(F) La solution d'Alex Martelli est grande en ce qu'il se passe vous. Cependant, vous devriez lire la section sur la classe Cell dans les xlrd docs: types de cellules sont texte, nombre, booléen, date, erreur, vide et vide. Si vous avez des dates, vous allez vouloir les formater des dates non des chiffres, de sorte que vous ne pouvez pas utiliser isinstance () (et vous ne voulez pas les frais généraux d'appel de la fonction de toute façon) ... c'est ce que l'attribut Cell.ctype et Sheet.cell_type() et les méthodes de Sheet.row_types() sont pour.

(G) UTF8 n'est pas Unicode. UTF16LE n'est pas Unicode. UTF16 n'est pas Unicode ... et l'idée que les chaînes individuelles gaspilleraient 2 octets chacun sur une nomenclature UTF16 est trop saugrenue même pour les États membres à envisager: -)

(H) Lectures complémentaires (mis à part les documents xlrd):

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

On dirait que vous avez 2 problèmes.

Il y a quelque chose foiré dans cette cellule - « 7 » doit être codé comme u'x37 je pense, car il est dans la plage ASCII

.

Plus important encore, le fait que vous obtenez un message d'erreur indiquant que le codec ascii ne peut pas être utilisé suggère tort de quelque chose avec votre encodage en unicode - il pense que vous essayez de coder une 0xed de valeur qui peut » t être représenté en ASCII, mais vous avez dit que vous essayez de le représenter dans unicode.

Je ne suis pas assez intelligent pour travailler quelle ligne particulière est la cause du problème - si vous modifiez votre question pour me dire ce ligne provoque ce message d'erreur que je pourrais être en mesure d'aider un peu plus (je suppose que c'est soit this_row.append(s.cell_value(row,col)) ou bcw.writerow(this_row), mais vous apprécierais confirmer).

Il semble y avoir deux possibilités. L'un est à juste titre que vous avez peut-être pas ouvert le fichier de sortie:

« Si csvfile est un objet fichier, il doit être ouvert avec le drapeau « b » sur les plateformes où cela fait une différence. » ( http://docs.python.org/library/csv.html#module -csv )

Si tel est le problème, alors une autre option pour vous est d'utiliser codecs.EncodedFile (fichier, entrée [, sortie [, erreurs]]) comme emballage pour la sortie de votre .csv:

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

Cela vous permettra d'avoir le filtre d'objet de fichier de UTF16 entrant en UTF8. Bien que les deux sont techniquement « unicode », la façon dont ils encodent est très différent.

Quelque chose comme ceci:

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

peut résoudre le problème pour vous, en supposant que je compris le problème droit, et en supposant que l'erreur est renvoyée lors de l'écriture dans le fichier.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top