Je suis en train de m'emmêler lamentablement les pinceaux sur un
problème de codage de string après avoir récupéré des données d'un
fichier excel avec win32com.client.
Et a un moment je l'écris dans un fichier :
save_file.write(rawtext)
Et je retrouve des caractères /xe9 et /xe8 à la place de é et è dans la
console et mon fichier.
Le contexte c'est python 2.6 sur XP
je ne sais pas si ça compte mais
un locale.getlocale() me donne (None, None)
Comment faire pour trouver quel est le code (standard?) du fichier xls
et le communiquer à python pour que les caractères s'inscrivent
correctement dans le fichier ?
Quel est le type de val ? C'est un str ou un unicode. Il faudrait faire un print type(val) pour le savoir. J'imagine que ça doit être un str et si c'est le cas il faudrait connaître l'encodage. Je ne sais pas s'il y ait un moyen de le connaître avec Python (je ne pense pas). On peut imaginer que c'est l'encodage cp1252 car c'est l'encodage par défaut sous Windows je crois.
rawtext=rawtext+repr(val.encode("iso-8859-1" ))
Cette ligne ne va pas je pense. Si on suppose que que val est de type str encodé en cp1252, il faut faire :
rawtext = rawtext + val.decode('cp1252') (comme ça on additionne de l'unicode avec de l'unicode.)
Et a un moment je l'écris dans un fichier : save_file.write(rawtext)
Là non plus, ça ne va pas. Quand on utilise f.write(), il faut passer en argument du str pas de l'unicode. L'unicode, c'est ce qu'il faut manipuler dans le programme (car il n'y a pas de souci d'encodage justement). En revanche, quand on veut lire ou écrire dans un fichier, on manipule du str et c'est le programmeur qui doit connaître les encodages. En gros, on m'avait expliqué ceci :
1) Quand on lit un fichier, on récupère du str et c'est à nous de connaître l'encodage du texte qu'on récupère. Ça dépend de l'application qui a créé les données. Sous Excel, comment sont encodées les chaînes caractères ? Je l'ignore mais ça ne concerne plus Python.
2) On s'empresse de convertir le str en unicode via :
chaine_unicode = chaine_str.decode('encodage du str récupéré')
Puis on manipule du unicode uniquement.
3) Quand on veut écrire dans un fichier les chaines unicode qu'on a manipulées dans 2), on utilise :
f.writre(chaine_unicode.encode('encodage'))
Et là on utilise l'encodage qu'on veut sauf si on veut lire les données avec une application particulière qui utilise peut-être uniquement tel ou tel encodage, mais là aussi c'est à nous de le savoir, ce n'est plus un problème Python.
Quel est le type de val ? C'est un str ou un unicode. Il faudrait faire
un print type(val) pour le savoir. J'imagine que ça doit être un str et
si c'est le cas il faudrait connaître l'encodage. Je ne sais pas s'il y
ait un moyen de le connaître avec Python (je ne pense pas). On peut
imaginer que c'est l'encodage cp1252 car c'est l'encodage par défaut
sous Windows je crois.
rawtext=rawtext+repr(val.encode("iso-8859-1" ))
Cette ligne ne va pas je pense. Si on suppose que que val est de type
str encodé en cp1252, il faut faire :
rawtext = rawtext + val.decode('cp1252')
(comme ça on additionne de l'unicode avec de l'unicode.)
Et a un moment je l'écris dans un fichier :
save_file.write(rawtext)
Là non plus, ça ne va pas. Quand on utilise f.write(), il faut passer en
argument du str pas de l'unicode. L'unicode, c'est ce qu'il faut
manipuler dans le programme (car il n'y a pas de souci d'encodage
justement). En revanche, quand on veut lire ou écrire dans un fichier,
on manipule du str et c'est le programmeur qui doit connaître les
encodages. En gros, on m'avait expliqué ceci :
1) Quand on lit un fichier, on récupère du str et c'est à nous de
connaître l'encodage du texte qu'on récupère. Ça dépend de l'application
qui a créé les données. Sous Excel, comment sont encodées les chaînes
caractères ? Je l'ignore mais ça ne concerne plus Python.
2) On s'empresse de convertir le str en unicode via :
chaine_unicode = chaine_str.decode('encodage du str récupéré')
Puis on manipule du unicode uniquement.
3) Quand on veut écrire dans un fichier les chaines unicode qu'on a
manipulées dans 2), on utilise :
f.writre(chaine_unicode.encode('encodage'))
Et là on utilise l'encodage qu'on veut sauf si on veut lire les données
avec une application particulière qui utilise peut-être uniquement tel
ou tel encodage, mais là aussi c'est à nous de le savoir, ce n'est plus
un problème Python.
Quel est le type de val ? C'est un str ou un unicode. Il faudrait faire un print type(val) pour le savoir. J'imagine que ça doit être un str et si c'est le cas il faudrait connaître l'encodage. Je ne sais pas s'il y ait un moyen de le connaître avec Python (je ne pense pas). On peut imaginer que c'est l'encodage cp1252 car c'est l'encodage par défaut sous Windows je crois.
rawtext=rawtext+repr(val.encode("iso-8859-1" ))
Cette ligne ne va pas je pense. Si on suppose que que val est de type str encodé en cp1252, il faut faire :
rawtext = rawtext + val.decode('cp1252') (comme ça on additionne de l'unicode avec de l'unicode.)
Et a un moment je l'écris dans un fichier : save_file.write(rawtext)
Là non plus, ça ne va pas. Quand on utilise f.write(), il faut passer en argument du str pas de l'unicode. L'unicode, c'est ce qu'il faut manipuler dans le programme (car il n'y a pas de souci d'encodage justement). En revanche, quand on veut lire ou écrire dans un fichier, on manipule du str et c'est le programmeur qui doit connaître les encodages. En gros, on m'avait expliqué ceci :
1) Quand on lit un fichier, on récupère du str et c'est à nous de connaître l'encodage du texte qu'on récupère. Ça dépend de l'application qui a créé les données. Sous Excel, comment sont encodées les chaînes caractères ? Je l'ignore mais ça ne concerne plus Python.
2) On s'empresse de convertir le str en unicode via :
chaine_unicode = chaine_str.decode('encodage du str récupéré')
Puis on manipule du unicode uniquement.
3) Quand on veut écrire dans un fichier les chaines unicode qu'on a manipulées dans 2), on utilise :
f.writre(chaine_unicode.encode('encodage'))
Et là on utilise l'encodage qu'on veut sauf si on veut lire les données avec une application particulière qui utilise peut-être uniquement tel ou tel encodage, mais là aussi c'est à nous de le savoir, ce n'est plus un problème Python.
J'espère ne pas avoir trop dit de bêtises.
-- François Lafont
Francois Lafont
Le 24/06/2011 13:47, Francois Lafont a écrit :
On peut imaginer que c'est l'encodage cp1252 car c'est l'encodage par défaut sous Windows je crois.
Après avoir fait une petite recherche rapide sur le Web, il semble bien que ce soit ça. Donc je dirais qu'un truc dans le genre ci-dessous devrait marcher :
On peut
imaginer que c'est l'encodage cp1252 car c'est l'encodage par défaut
sous Windows je crois.
Après avoir fait une petite recherche rapide sur le Web, il semble bien
que ce soit ça. Donc je dirais qu'un truc dans le genre ci-dessous
devrait marcher :
On peut imaginer que c'est l'encodage cp1252 car c'est l'encodage par défaut sous Windows je crois.
Après avoir fait une petite recherche rapide sur le Web, il semble bien que ce soit ça. Donc je dirais qu'un truc dans le genre ci-dessous devrait marcher :
On peut imaginer que c'est l'encodage cp1252 car c'est l'encodage par défaut sous Windows je crois.
Après avoir fait une petite recherche rapide sur le Web, il semble bien que ce soit ça. Donc je dirais qu'un truc dans le genre ci-dessous devrait marcher :
rawtext=rawtext+val.decode('cp1252') ou encore rawtext=rawtext+val.decode('iso-8859-1')
Me donne une erreur unicodeEncodeError Ordinal not in range(128) dès qu'une cellule contient un caractère accentué. Je ne comprends pas : 'é' est un caractère unicode, et il devrait bien avoir une représentation valide en cp1252, non ?
Francois Lafont a écrit le 24/06/2011 :
Le 24/06/2011 13:47, Francois Lafont a écrit :
On peut
imaginer que c'est l'encodage cp1252 car c'est l'encodage par défaut
sous Windows je crois.
Après avoir fait une petite recherche rapide sur le Web, il semble bien
que ce soit ça. Donc je dirais qu'un truc dans le genre ci-dessous
devrait marcher :
rawtext=rawtext+val.decode('cp1252')
ou encore
rawtext=rawtext+val.decode('iso-8859-1')
Me donne une erreur unicodeEncodeError Ordinal not in range(128) dès
qu'une cellule contient un caractère accentué. Je ne comprends pas :
'é' est un caractère unicode, et il devrait bien avoir une
représentation valide en cp1252, non ?
On peut imaginer que c'est l'encodage cp1252 car c'est l'encodage par défaut sous Windows je crois.
Après avoir fait une petite recherche rapide sur le Web, il semble bien que ce soit ça. Donc je dirais qu'un truc dans le genre ci-dessous devrait marcher :
rawtext=rawtext+val.decode('cp1252') ou encore rawtext=rawtext+val.decode('iso-8859-1')
Me donne une erreur unicodeEncodeError Ordinal not in range(128) dès qu'une cellule contient un caractère accentué. Je ne comprends pas : 'é' est un caractère unicode, et il devrait bien avoir une représentation valide en cp1252, non ?
Francois Lafont
Le 24/06/2011 15:21, val a écrit :
Merci pour la réponse.
rawtext=rawtext+val.decode('cp1252') ou encore rawtext=rawtext+val.decode('iso-8859-1')
Me donne une erreur unicodeEncodeError Ordinal not in range(128) dès qu'une cellule contient un caractère accentué.
Pourrais-tu fournir un ECM (Exemple Complet et Minimal) et donner le message d'erreur tel quel ?
-- François Lafont
Le 24/06/2011 15:21, val a écrit :
Merci pour la réponse.
rawtext=rawtext+val.decode('cp1252')
ou encore
rawtext=rawtext+val.decode('iso-8859-1')
Me donne une erreur unicodeEncodeError Ordinal not in range(128) dès
qu'une cellule contient un caractère accentué.
Pourrais-tu fournir un ECM (Exemple Complet et Minimal) et donner le
message d'erreur tel quel ?
Si tu attaques Excel avec win32com.client, c'est que tu passes par COM. Et COM retourne, pour les chaines, de l'Unicode. Donc, inutile de décoder la valeur reçue.
Concentre-toi donc sur l'encodage dont tu as besoin.
Sinon, j'ai relevé : - que tu uilises l'encodage sans paramètre de gestion d'erreur. Tu devrais préciser 'ignore', plutôt que le 'strict' par défaut. - la fonction repr() est inutile (c'est elle qui remplace les caractères par ce que tu crois être des trucs bizarres).
Enfin, si tu utilises beaucoup, ou souvent, Excel depuis Python, j'avais écris une classe toute prête. Mais on peut aussi préférer ré-inventer la roue ; ce qui est souvent très instructif... (http://www.ponx.org/download/CD/PONX/pxexcel.py)
@+ -- Michel Claveau
Bonsoir !
Si tu attaques Excel avec win32com.client, c'est que tu passes par COM.
Et COM retourne, pour les chaines, de l'Unicode. Donc, inutile de décoder
la valeur reçue.
Concentre-toi donc sur l'encodage dont tu as besoin.
Sinon, j'ai relevé :
- que tu uilises l'encodage sans paramètre de gestion d'erreur. Tu devrais
préciser 'ignore', plutôt que le 'strict' par défaut.
- la fonction repr() est inutile (c'est elle qui remplace les caractères
par ce que tu crois être des trucs bizarres).
Enfin, si tu utilises beaucoup, ou souvent, Excel depuis Python, j'avais
écris une classe toute prête. Mais on peut aussi préférer ré-inventer la
roue ; ce qui est souvent très instructif...
(http://www.ponx.org/download/CD/PONX/pxexcel.py)
Si tu attaques Excel avec win32com.client, c'est que tu passes par COM. Et COM retourne, pour les chaines, de l'Unicode. Donc, inutile de décoder la valeur reçue.
Concentre-toi donc sur l'encodage dont tu as besoin.
Sinon, j'ai relevé : - que tu uilises l'encodage sans paramètre de gestion d'erreur. Tu devrais préciser 'ignore', plutôt que le 'strict' par défaut. - la fonction repr() est inutile (c'est elle qui remplace les caractères par ce que tu crois être des trucs bizarres).
Enfin, si tu utilises beaucoup, ou souvent, Excel depuis Python, j'avais écris une classe toute prête. Mais on peut aussi préférer ré-inventer la roue ; ce qui est souvent très instructif... (http://www.ponx.org/download/CD/PONX/pxexcel.py)
@+ -- Michel Claveau
val
Francois Lafont a écrit le 25/06/2011 :
Pourrais-tu fournir un ECM (Exemple Complet et Minimal) et donner le message d'erreur tel quel ?
Désolé pour le retard, je n'étais pas là ce week-end...
J'ai essayé de faire un exemple minimal et ça donne ça :
save_file=file('log.dat', 'w') rawtext=u'' val=u'problème' print type(val), val rawtext=rawtext+val.encode('cp1252') # <-- c'est la ligne 11 try: #print u save_file.write(rawtext.encode('cp1252')+'n') except: print "xxxx", str(rawtext), sys.exc_info() save_file.close()
le message complet d'erreur est le suivant :
F:pythontest>ECM.py <type 'unicode'> problème Traceback (most recent call last): File "F:pythontestECM.py", line 11, in <module> rawtext=rawtext+val.encode('cp1252') UnicodeDecodeError: 'ascii' codec can't decode byte 0xe8 in position 5: ordinal not in range(128)
Je ne sais vraiment pas comment faire pour convertir et afficher le unicode venant d'excel...
Francois Lafont a écrit le 25/06/2011 :
Pourrais-tu fournir un ECM (Exemple Complet et Minimal) et donner le
message d'erreur tel quel ?
Désolé pour le retard, je n'étais pas là ce week-end...
J'ai essayé de faire un exemple minimal et ça donne ça :
save_file=file('log.dat', 'w')
rawtext=u''
val=u'problème'
print type(val), val
rawtext=rawtext+val.encode('cp1252') # <-- c'est la ligne 11
try:
#print u
save_file.write(rawtext.encode('cp1252')+'n')
except:
print "xxxx", str(rawtext), sys.exc_info()
save_file.close()
le message complet d'erreur est le suivant :
F:pythontest>ECM.py
<type 'unicode'> problème
Traceback (most recent call last):
File "F:pythontestECM.py", line 11, in <module>
rawtext=rawtext+val.encode('cp1252')
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe8 in position 5:
ordinal not in range(128)
Je ne sais vraiment pas comment faire pour convertir et afficher le
unicode venant d'excel...
save_file=file('log.dat', 'w') rawtext=u'' val=u'problème' print type(val), val rawtext=rawtext+val.encode('cp1252') # <-- c'est la ligne 11 try: #print u save_file.write(rawtext.encode('cp1252')+'n') except: print "xxxx", str(rawtext), sys.exc_info() save_file.close()
le message complet d'erreur est le suivant :
F:pythontest>ECM.py <type 'unicode'> problème Traceback (most recent call last): File "F:pythontestECM.py", line 11, in <module> rawtext=rawtext+val.encode('cp1252') UnicodeDecodeError: 'ascii' codec can't decode byte 0xe8 in position 5: ordinal not in range(128)
Je ne sais vraiment pas comment faire pour convertir et afficher le unicode venant d'excel...
Francois Lafont
Le 27/06/2011 10:39, val a écrit :
J'ai essayé de faire un exemple minimal et ça donne ça :
Je constate que finalement, dans ton ECM, il n'est même plus question d'Excel.
save_file=file('log.dat', 'w') rawtext=u'' val=u'problème' print type(val), val rawtext=rawtext+val.encode('cp1252')
Normal que ça plante ici. val est de l'unicode et rawtext aussi. Ils sont de même type. Donc il n'y a rien à faire à part simplement :
rawtext = rawtext + val
Je ne sais vraiment pas comment faire pour convertir et afficher le unicode venant d'excel...
D'après Michel, ce que tu obtiens venant d'Excel est de l'unicode directement donc tu n'as rien à convertir au départ. Tu fais juste bien gaffe de manipuler ces chaînes unicode avec d'autres chaînes unicode également c'est tout.
Le seul moment où il faudra convertir en str, c'est quand tu voudras écrire dans un fichier :
save_file=file('log.dat', 'w')
rawtext=u''
val=u'problème'
print type(val), val
rawtext=rawtext+val.encode('cp1252')
Normal que ça plante ici. val est de l'unicode et rawtext aussi. Ils
sont de même type. Donc il n'y a rien à faire à part simplement :
rawtext = rawtext + val
Je ne sais vraiment pas comment faire pour convertir et afficher le
unicode venant d'excel...
D'après Michel, ce que tu obtiens venant d'Excel est de l'unicode
directement donc tu n'as rien à convertir au départ. Tu fais juste bien
gaffe de manipuler ces chaînes unicode avec d'autres chaînes unicode
également c'est tout.
Le seul moment où il faudra convertir en str, c'est quand tu voudras
écrire dans un fichier :
save_file=file('log.dat', 'w') rawtext=u'' val=u'problème' print type(val), val rawtext=rawtext+val.encode('cp1252')
Normal que ça plante ici. val est de l'unicode et rawtext aussi. Ils sont de même type. Donc il n'y a rien à faire à part simplement :
rawtext = rawtext + val
Je ne sais vraiment pas comment faire pour convertir et afficher le unicode venant d'excel...
D'après Michel, ce que tu obtiens venant d'Excel est de l'unicode directement donc tu n'as rien à convertir au départ. Tu fais juste bien gaffe de manipuler ces chaînes unicode avec d'autres chaînes unicode également c'est tout.
Le seul moment où il faudra convertir en str, c'est quand tu voudras écrire dans un fichier :
Normal que ça plante ici. val est de l'unicode et rawtext aussi. Ils sont de même type. Donc il n'y a rien à faire à part simplement :
rawtext = rawtext + val
Pour être précis, le val.encode('cp1252') n'a aucun sens pour moi car rawtext est de l'unicode et val aussi donc on peut/doit les additionner directement. C'est ça qu'il faut retenir.
Ceci étant dit, ce n'est pas le val.encode('cp1252') qui provoque une erreur ici. L'instruction val.encode('cp1252') toute seule est parfaitement licite et elle renvoie un str encodé en cp1252. Mais comme tu additionnes un unicode (rawtext) avec un str (val.encode('cp1252')), il va chercher à convertir le str en unicode et en fait :
ton « rawtext = rawtext + val.encode('cp1252') » revient en fait à ça :
(conversion implicite du str en unicode, mais par défaut Python part du principe que le str est en ascii.)
Et là boum ! Erreur puisque que le str val.encode('cp1252') n'est pas 100% ASCII.
-- François Lafont
Le 28/06/2011 01:00, Francois Lafont a écrit :
rawtext=rawtext+val.encode('cp1252')
Normal que ça plante ici. val est de l'unicode et rawtext aussi. Ils
sont de même type. Donc il n'y a rien à faire à part simplement :
rawtext = rawtext + val
Pour être précis, le val.encode('cp1252') n'a aucun sens pour moi car
rawtext est de l'unicode et val aussi donc on peut/doit les additionner
directement. C'est ça qu'il faut retenir.
Ceci étant dit, ce n'est pas le val.encode('cp1252') qui provoque une
erreur ici. L'instruction val.encode('cp1252') toute seule est
parfaitement licite et elle renvoie un str encodé en cp1252. Mais comme
tu additionnes un unicode (rawtext) avec un str (val.encode('cp1252')),
il va chercher à convertir le str en unicode et en fait :
ton « rawtext = rawtext + val.encode('cp1252') » revient en fait à ça :
Normal que ça plante ici. val est de l'unicode et rawtext aussi. Ils sont de même type. Donc il n'y a rien à faire à part simplement :
rawtext = rawtext + val
Pour être précis, le val.encode('cp1252') n'a aucun sens pour moi car rawtext est de l'unicode et val aussi donc on peut/doit les additionner directement. C'est ça qu'il faut retenir.
Ceci étant dit, ce n'est pas le val.encode('cp1252') qui provoque une erreur ici. L'instruction val.encode('cp1252') toute seule est parfaitement licite et elle renvoie un str encodé en cp1252. Mais comme tu additionnes un unicode (rawtext) avec un str (val.encode('cp1252')), il va chercher à convertir le str en unicode et en fait :
ton « rawtext = rawtext + val.encode('cp1252') » revient en fait à ça :
(conversion implicite du str en unicode, mais par défaut Python part du principe que le str est en ascii.)
Et là boum ! Erreur puisque que le str val.encode('cp1252') n'est pas 100% ASCII.
-- François Lafont
val
Michel Claveau - MVP a écrit le 26/06/2011 :
Bonsoir !
Si tu attaques Excel avec win32com.client, c'est que tu passes par COM. Et COM retourne, pour les chaines, de l'Unicode. Donc, inutile de décoder la valeur reçue.
Concentre-toi donc sur l'encodage dont tu as besoin.
Sinon, j'ai relevé : - que tu uilises l'encodage sans paramètre de gestion d'erreur. Tu devrais préciser 'ignore', plutôt que le 'strict' par défaut. - la fonction repr() est inutile (c'est elle qui remplace les caractères par ce que tu crois être des trucs bizarres).
Enfin, si tu utilises beaucoup, ou souvent, Excel depuis Python, j'avais écris une classe toute prête. Mais on peut aussi préférer ré-inventer la roue ; ce qui est souvent très instructif... (http://www.ponx.org/download/CD/PONX/pxexcel.py)
@+
En fait je vous ai déja 'piqué' votre script car je suis parti de :
Si tu attaques Excel avec win32com.client, c'est que tu passes par COM.
Et COM retourne, pour les chaines, de l'Unicode. Donc, inutile de décoder
la valeur reçue.
Concentre-toi donc sur l'encodage dont tu as besoin.
Sinon, j'ai relevé :
- que tu uilises l'encodage sans paramètre de gestion d'erreur. Tu devrais
préciser 'ignore', plutôt que le 'strict' par défaut.
- la fonction repr() est inutile (c'est elle qui remplace les caractères
par ce que tu crois être des trucs bizarres).
Enfin, si tu utilises beaucoup, ou souvent, Excel depuis Python, j'avais
écris une classe toute prête. Mais on peut aussi préférer ré-inventer la
roue ; ce qui est souvent très instructif...
(http://www.ponx.org/download/CD/PONX/pxexcel.py)
@+
En fait je vous ai déja 'piqué' votre script car je suis parti de :
Si tu attaques Excel avec win32com.client, c'est que tu passes par COM. Et COM retourne, pour les chaines, de l'Unicode. Donc, inutile de décoder la valeur reçue.
Concentre-toi donc sur l'encodage dont tu as besoin.
Sinon, j'ai relevé : - que tu uilises l'encodage sans paramètre de gestion d'erreur. Tu devrais préciser 'ignore', plutôt que le 'strict' par défaut. - la fonction repr() est inutile (c'est elle qui remplace les caractères par ce que tu crois être des trucs bizarres).
Enfin, si tu utilises beaucoup, ou souvent, Excel depuis Python, j'avais écris une classe toute prête. Mais on peut aussi préférer ré-inventer la roue ; ce qui est souvent très instructif... (http://www.ponx.org/download/CD/PONX/pxexcel.py)
@+
En fait je vous ai déja 'piqué' votre script car je suis parti de :