J’avais oublié la zik, je rajoute:
Vous avez tous un jour eu l’erreur suivante :
UnicodeDecodeError: 'machine' codec can't decode character 'trucmuche' in position x: ordinal not in range(z) |
Et là, pour vous en sortir, vous en avez chié des ronds de pâté.
Le problème vient du fait que la plupart du temps, ignorer l’encoding marche : nous travaillons dans des environnements homogènes et toujours avec des données dans le même format, ou un format plus ou moins compatible.
Mais le texte, c’est compliqué, terriblement compliqué, et le jour où ça se gâte, si vous ne savez pas ce que vous faites, vous ne vous en sortirez pas.
C’est d’autant plus vrai en Python car :
- Par défaut, Python plante sur les erreurs d’encoding là où d’autres langages (comme le PHP) se débrouillent pour vous sortir un truc (qui ne veut rien dire, qui peut corrompre toute votre base de données, mais qui ne plante pas).
- Python est utilisé dans des environnements hétérogènes. Quand vous codez en JS sur le navigateur, vous n’avez presque jamais à vous soucier de l’encoding : le browser gère quasiment tout pour vous. En Python dès que vous allez lire un fichier et l’afficher dans un terminal, cela fait potentiellement 3 encoding différents.
- Python 2.7 a des réglages par défaut très stricts, et pas forcément adaptés à notre informatique moderne (fichier de code en ASCII par exemple).
A la fin de cet article, vous saurez vous sortir de toutes les situations merdiques liées aux encodages.
Règle numéro 1 : Le texte brut n’existe pas.
Quand vous avez du texte quelque part (un terminal, un fichier, une base de données…), il est forcément représenté sous forme de 0 et de 1.
La corrélation entre cette suite de 0 et de 1 et la lettre est faite dans un énorme tableau qui contient toutes les lettres d’un côté, et toutes les combinaisons de 0 et de 1 de l’autre. Il n’y a pas de magie. C’est un énorme tableau stocké quelque part dans votre ordinateur. Si vous n’avez pas ce tableau, vous ne pouvez pas lire du texte. Même le texte le plus simple.
Malheureusement, au début de l’informatique, presque chaque pays a créé son propre tableau, et ces tableaux sont incompatibles entre eux : pour la même combinaison de 0 et de 1, ils donnent un caractère différent voire rien du tout.
La mauvaise nouvelle, c’est qu’ils sont encore utilisés aujourd’hui.
Ces tableaux, c’est ce qu’on appelle les encodings, et il y en a beaucoup. Voici la liste de ceux que Python gère :
>>> import encodings >>> print ''.join('- ' + e + '\n' for e in sorted(set(encodings.aliases.aliases.values()))) - ascii - base64_codec - big5 - big5hkscs - bz2_codec - cp037 - cp1026 - cp1140 - cp1250 - cp1251 - cp1252 - cp1253 - cp1254 - cp1255 - cp1256 - cp1257 - cp1258 - cp424 - cp437 - cp500 - cp775 - cp850 - cp852 - cp855 - cp857 - cp858 - cp860 - cp861 - cp862 - cp863 - cp864 - cp865 - cp866 - cp869 - cp932 - cp949 - cp950 - euc_jis_2004 - euc_jisx0213 - euc_jp - euc_kr - gb18030 - gb2312 - gbk - hex_codec - hp_roman8 - hz - iso2022_jp - iso2022_jp_1 - iso2022_jp_2 - iso2022_jp_2004 - iso2022_jp_3 - iso2022_jp_ext - iso2022_kr - iso8859_10 - iso8859_11 - iso8859_13 - iso8859_14 - iso8859_15 - iso8859_16 - iso8859_2 - iso8859_3 - iso8859_4 - iso8859_5 - iso8859_6 - iso8859_7 - iso8859_8 - iso8859_9 - johab - koi8_r - latin_1 - mac_cyrillic - mac_greek - mac_iceland - mac_latin2 - mac_roman - mac_turkish - mbcs - ptcp154 - quopri_codec - rot_13 - shift_jis - shift_jis_2004 - shift_jisx0213 - tactis - tis_620 - utf_16 - utf_16_be - utf_16_le - utf_32 - utf_32_be - utf_32_le - utf_7 - utf_8 - uu_codec - zlib_codec |
Et certains ont plusieurs noms (des alias), donc on pourrait en compter plus:
>>> len(encodings.aliases.aliases.keys()) 307 |
Quand vous affichez du texte sur un terminal avec un simple print
, votre ordinateur va implicitement chercher le tableau qu’il pense être le plus adapté, et fait la traduction. Même pour le texte le plus simple. Même pour un espace tout seul.
Mais surtout, ça veut dire que votre propre code EST dans un encoding. Et vous DEVEZ savoir lequel.
Règle numéro 2 : utf8 est le langage universel, utilisez-le
Il existe un encoding qui essaye des regrouper toutes les langues du monde, et il s’appelle unicode. Unicode est un tableau gigantesque qui contient des combinaisons de 1 et de 0 d’un côté, et les caractères de toutes la langues possibles de l’autre : chinois, arabe, français, espagnol, russe…
Bon, il ne contient pas encore absolument tout, mais il couvre suffisamment de terrain pour éliminer 99.999999999% des problèmes de communications de texte entre machines dans le monde.
Le défaut d’Unicode est qu’il est plus lent et prend plus de place que d’autres représentations du même texte. Aujourd’hui le téléphone le plus pourri a 10 fois la puissance nécessaire, et ce n’est plus un souci : il peut être utilisé presque partout (sauf peut-être dans l’embarqué drastique) sans même réfléchir à la question. Tous les langages les plus importants, tous les services les plus importants, tous les logiciels les plus importants gèrent unicode.
Il y a plusieurs implémentations concrètes d’unicode, la plus célèbre est “UTF 8″.
Moralité, par défaut, utilisez utf-8.
Une fois, à l’entretien d’embauche, un mec m’avait reproché d’utiliser UTF8 parce que “ça posait des problèmes d’encoding”. Comprenez bien qu’utf-8 ne pose aucun problème d’encoding. Ce sont tous les autres codecs du monde qui posent des problèmes d’encoding. UTF-8 est certainement le seul à justement, ne poser aucun problème.
UTF 8 est le seul encoding vers lequel, aujourd’hui, on puisse convertir vers et depuis (pratiquement) n’importe quel autre codec du monde. C’est un espéranto. C’est une pierre de rosette. C’est au texte ce que l’or est à l’économie.
Si UTF8 vous pose “un problème d’encoding”, c’est que vous ne savez pas dans quel encoding votre texte est actuellement ou comment le convertir. C’est tout.
Il n’y a presque aucune raison de ne pas utiliser UTF8 aujourd’hui (à part sur des vieux systèmes ou des systèmes où les ressources sont tellement limitées que vous n’utiliseriez pas Python de toute façon).
Utilisez utf8. Partout. Tout le temps.
Si vous communiquez avec un système qui ne comprend pas UTF8, convertissez.
Mais gardez votre partie en UTF8.
Règle numéro 3 : il faut maîtriser l’encoding de son code
Le fichier dans lequel vous écrivez votre code est dans un encoding et ce n’est pas lié à votre OS. C’est votre éditeur qui s’en occupe. Apprenez à régler votre éditeur pour qu’il utilise l’encoding que vous voulez.
Et l’encoding que vous voulez est UTF8.
Si vous ne savez pas dans quel encoding est votre code, vous ne pouvez pas manipuler du texte et garantir l’absence de bug.
Vous ne POUVEZ PAS.
Donc réflexe : vous configurez votre éditeur de texte pour sauvegarder tous vos nouveaux fichiers par défaut en UTF8. Maintenant. Tout de suite.
Regardez dans la doc de l’éditeur, dans l’aide ou tapez sur Google, mais faites le.
Puis il faut déclarer cet encoding à la première ligne de chaque fichier de code avec l’expression suivante :
# coding: encoding |
Par exemple :
# coding: utf8 |
C’est une spécificité de Python : si l’encoding du fichier est différent de l’encoding par défaut du langage, il faut le déclarer sinon le programme plantera à la première conversion. En Python 2.7, l’encoding par défaut est ASCII, donc il faut presque toujours le déclarer. En Python 3, l’encoding par défaut est UTF8 et on peut donc l’omettre si on l’utilise. Ce que vous allez faire après la lecture de cet article.
Ensuite, il existe deux types de chaînes de caractères en Python :
- La chaîne de caractères encodée: type ‘str’ en Python 2.7, ‘byte’ en Python 3.
- La chaîne de caractères décodée: type ‘unicode’ en Python 2.7, et ‘str’ en python 3 (sic).
Illustration :
$ python2.7 Python 2.7.3 (default, Aug 1 2012, 05:14:39) [GCC 4.6.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> type('chaine') # bits => encodée <type 'str'> >>> type(u'chaine') # unicode => décodée <type 'unicode'> |
$ python3 Python 3.2.3 (default, Oct 19 2012, 20:10:41) [GCC 4.6.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> type("chaine") # unicode => decodée <class 'str'> >>> type(b"chaine") # bits => encodée <class 'bytes'> |
Votre but, c’est de n’avoir dans votre code que des chaînes de type ‘unicode’.
En Python 3, c’est automatique. Toutes les chaînes sont de type ‘unicode’ (appelé ‘str’ dans cette version, je sais, je sais, c’est confusionant à mort) par défaut.
En Python 2.7 en revanche, il faut préfixer la chaîne par un u
.
Donc, dans votre code, TOUTES vos chaînes doivent être déclarées ainsi :
u"votre chaîne" |
Oui, c’est chiant. Mais c’est indispensable. Encore une fois, il n’y a pas d’alternative (dites le avec la voix de Thatcher si ça vous excite).
Si vous voulez, vous pouvez activer le comportement de Python 3 dans Python 2.7 en mettant ceci au début de CHACUN de vos modules :
from __future__ import unicode_literals |
Ceci n’affecte que le fichier en cours, jamais les autres modules.
On peut le mettre au démarrage d’iPython également.
Je résume :
- Réglez votre éditeur sur UTF8.
- Mettez
# coding: utf8
au début de vos modules. - Préfixez toutes vos chaînes de
u
ou faitesfrom __future__ import unicode_literals
en début de chaque module.
Si vous ne faites pas cela, votre code marchera. La plupart de temps. Et un jour, dans une situation particulière, il ne marchera plus. Plus du tout.
Oh, et ce n’est pas grave si vous avez d’anciens modules dans d’autres encodings. Tant que vous utilisez des objets ‘unicode’ partout, ils marcheront sans problème ensemble.
Règle numéro 4 : décodez toutes les entrées de votre programme
La partie difficile de ce conseil, c’est de savoir ce qu’est une entrée.
Je vais vous donner une définition simple : tout ce qui ne fait pas partie du code de votre programme et qui est traité dans votre programme est une entrée.
Le texte des fichiers, le nom de ces fichiers, le retour des appels système, le retour d’une ligne de commande parsée, la saisie utilisateur sur un terminal, le retour d’une requête SQL, le téléchargement d’une donnée sur le Web, etc.
Ce sont toutes des entrées.
Comme tous les textes du monde, les entrées sont dans un encoding. Et vous DEVEZ savoir lequel.
Comprenez bien, si vous ne connaissez pas l’encoding de vos entrées, ça marchera la plupart du temps, et un jour, ça va planter.
Il n’y a pas d’alternative (bis).
Or, il n’y a pas de moyen de détecter un encoding de façon fiable.
Donc, soit le fournisseur de la donnée vous donne cette information (settings dans la base de données, doc de votre logiciel, configuration de votre OS, spec du client, coup de fils au fournisseur…), soit vous êtes baisés.
On ne peut pas lire un simple fichier si on ne connait pas son encoding. Point.
Si cela a marché jusqu’ici pour vous, c’est que vous avez eu de la chance : la plupart de vos fichiers étaient dans l’encoding de votre éditeur et de votre système. Tant qu’on travaille sur sa machine, tout va bien.
Si vous lisez une page HTML, l’encoding est souvent déclaré dans la balise META ou dans un header.
Si vous écrivez dans un terminal, l’encoding du terminal est accessible avec sys.(stdin|stdout).encoding
.
Si vous manipulez des noms de fichier, on peut récupérer l’encoding du file system en cours avec sys.getfilesystemencoding()
.
Mais parfois il n’y a pas d’autres moyens d’obtenir cette information que de demander à la personne qui a produit la donnée. Parfois même, l’encoding déclaré est faux.
Dans tous les cas, vous avez besoin de cette information.
Et une fois que vous l’avez, il faut décoder le texte reçu.
La manière la plus simple de faire cela est :
votre_chaine = votre_chaine.decode('nom_du_codec') |
Le texte sera de type ‘str’, et decode()
retourne (si vous lui fournissez le bon codec ;-)), une version ‘unicode’.
Exemple, obtenir une chaîne ‘unicode’ depuis une chaîne ‘str’ encodée en utf8 :
>>> une_chaine = 'Chaîne' # mon fichier est encodé en UTF8, donc la chaine est en UTF8 >>> type(une_chaine) <type 'str'> >>> une_chaine = une_chaine.decode('utf8') >>> type(une_chaine) <type 'unicode'> |
Donc dès que vous lisez un fichier, récupérez une réponse d’une base de données ou parsez des arguments d’un terminal, appelez decode()
sur la chaîne reçue.
Règle numéro 5 : encodez toutes les sorties de votre programme
La partie difficile de ce conseil, c’est de savoir ce qu’est une sortie.
Encore une fois, une définition simple : toute donnée que vous traitez et qui va être lue par autre chose que votre code est une sortie.
Un print
dans un terminal est une sortie, un write()
dans un fichier est une sortie, un UPDATE
en SQL est une sortie, un envoi dans une socket est une sortie, etc.
Le reste du monde ne peut pas lire les objets ‘unicode’ de Python. Si vous écrivez ces objets dans un fichier, un terminal ou dans une base de données, Python va les convertir automatiquement en objet ‘str’, et l’encoding utilisé dépendra du contexte.
Malheureusement, il y a une limite à la capacité de Python à décider du bon encoding.
Donc, tout comme il vous faut connaitre l’encoding d’un texte en entrée, il vous faut connaitre l’encoding attendu par le système avec lequel vous communiquez en sortie : sachez quel est l’encoding du terminal, de votre base de données ou système de fichiers sur lequel vous écrivez.
Si vous ne pouvez pas savoir (page Web, API, etc), utilisez UTF8.
Pour ce faire, il suffit d’appelez encode()
sur tout objet de type ‘unicode’ :
une_chaine = une_chaine.encode('nom_du_codec') |
Par exemple, pour convertir un objet ‘unicode’ en ‘str’ utf8:
>>> une_chaine = u'Chaîne' >>> type(une_chaine) <type 'unicode'> >>> une_chaine = une_chaine.encode('utf8') >>> type(une_chaine) <type 'str'> |
Résumé des règles
- Le texte brut n’existe pas.
- Utilisez UTF8. Maintenant. Partout.
- Dans votre code, spécifiez l’encoding du fichier et déclarez vos chaînes comme ‘unicode’.
- À l’entrée, connaissez l’encoding de vos données, et décodez avec
decode()
. - A la sortie, encodez dans l’encoding attendu par le système qui va recevoir la données, ou si vous ne pouvez pas savoir, en UTF8, avec
encode()
.
Je sais que ça vous démange de voir un cas concret, alors voici un pseudo programme (téléchargeable ici) :
# coding: utf-8 # toutes les chaines sont en unicode (même les docstrings) from __future__ import unicode_literals """ Un script tout pourri qui télécharge plein de page et les sauvegarde dans une base de données sqlites. On écrit dans un fichier de log les opérations effectuées. """ import re import urllib2 import sqlite3 pages = ( ('Snippets de Sebsauvage', 'http://www.sebsauvage.net/python/snyppets/'), ('Top 50 de bashfr', 'http://danstonchat.com/top50.html'), ) # création de la base de données conn = sqlite3.connect(r"backup.db") c = conn.cursor() try: c.execute(''' CREATE TABLE pages ( id INTEGER PRIMARY KEY, nom TEXT, html TEXT )''' ) except sqlite3.OperationalError: pass log = open('backup.log', 'wa') for nom, page in pages: # ceci est une manière très fragile de télécharger et # parser du HTML. Utilisez plutôt scrapy et beautifulsoup # si vous faites un vrai crawler response = urllib2.urlopen(page) html = response.read(100000) # je récupère l'encoding à l'arrache encoding = re.findall(r'<meta.*?charset=["\']*(.+?)["\'>]', html, flags=re.I)[0] # html devient de l'unicode html = html.decode(encoding) # ici je peux faire des traitements divers et varié avec ma chaîne # et en fin de programme... # la lib sqlite convertie par défaut tout objet unicode en UTF8 # car c'est l'encoding de sqlite par défaut donc passer des chaînes # unicode marche, et toutes les chaînes de mon programme sont en unicode # grace à mon premier import c.execute("""INSERT INTO pages (nom, html) VALUES (?, ?)""", (nom, html)) # j'écris dans mon fichier en UTF8 car c'est ce que je veux pouvoir lire # plus tard msg = "Page '{}' sauvée\n".format(nom) log.write(msg.encode('utf8')) # notez que si je ne fais pas encode(), soit: # - j'ai un objet 'unicode' et ça plante # - j'ai un objet 'str' et ça va marcher mais mon fichier contiendra # l'encoding de la chaîne initiale (qui ici serait aussi UTF8, mais # ce n'est pas toujours le cas) conn.commit() c.close() log.close() |
Quelques astuces
Certaines bibliothèques acceptent indifféremment des objets ‘unicode’ et ‘str’ :
>>> from logging import basicConfig, getLogger >>> basicConfig() >>> log = getLogger() >>> log.warn("Détécé") WARNING:root:Détécé >>> log.warn(u"Détécé") WARNING:root:Détécé |
Et ce n’est pas forcément une bonne chose car si il y a derrière écriture dans un fichier de log, cela peut poser problème.
D’autres ont besoin qu’on leur précise:
>>> import re >>> import re >>> re.search('é', 'télé') <_sre.SRE_Match object at 0x7fa4d3f77238> >>> re.search(u'é', u'télé', re.UNICODE) <_sre.SRE_Match object at 0x7fa4d3f772a0> |
Le module re
par exemple aura des résultats biaisés sur une chaîne ‘unicode’ si on ne précise pas le flag re.UNICODE
.
D’autres n’acceptent pas d’objet ‘str':
>>> import io >>> >>> io.StringIO(u'é') <_io.StringIO object at 0x14a96d0> >>> io.StringIO(u'é'.encode('utf8')) Traceback (most recent call last): File "<ipython-input-5-16988a0d4ac4>", line 1, in <module> io.StringIO('é'.encode('utf8')) TypeError: initial_value must be unicode or None, not str |
D’autres encore n’acceptent pas d’objet ‘unicode':
>>> import base64 >>> base64.encodestring('é'.encode('utf8')) 'w6k=\n' >>> base64.encodestring(u'é') Traceback (most recent call last): File "<ipython-input-3-1714982ca68e>", line 1, in <module> base64.encodestring('é') File "/usr/lib/python2.7/base64.py", line 315, in encodestring pieces.append(binascii.b2a_base64(chunk)) UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 0: ordinal not in range(128) |
Cela peut être pour des raison de performances (certaines opérations sont plus rapides sur un objet ‘str’), ou pour des raisons historiques, d’ignorance ou de paresse.
Vous ne pouvez pas le deviner à l’avance. Souvent c’est marqué dans la doc, sinon il faut tester dans le shell.
Une bibliothèque bien faite demandera de l’unicode et vous retournera de l’unicode, vous libérant l’esprit. Par exemple, requests et l’ORM Django le font, et communiquent avec le reste du monde (en l’occurence le Web et les bases de données) dans le meilleur encoding possible automatiquement de manière transparente. Quand c’est possible bien entendu, parfois il faudra forcer l’encoding car le fournisseur de votre donnée déclare le mauvais. Vous n’y pouvez rien, c’est pareil pour tous les langages du monde.
Enfin il existe des raccourcis pour certaines opérations, utilisez-les autant que possible. Par exemple, pour lire un fichier, au lieu de faire un simple open()
, vous pouvez faire :
from codecs import open # open() de codec à exactement la même API, y compris avec "with" f = open('fichier', encoding='encoding') |
Les chaînes récupérées seront automatiquement sous forme d’objet ‘unicode’ au lieu d’objet ‘str’ qu’il vous aurait fallu convertir à la main.
Les outils de la dernière chance
Je vous ai menti, si vous ne connaissez pas l’encoding de vos entrées ou de vos sorties, il vous reste encore quelques options.
Sachez cependant que ces options sont des hacks, des trucs à tenter quand tout ce qui a été décrit plus haut a foiré.
Si vous faites bien votre boulot, ça ne doit pas arriver souvent. Une à deux fois max dans votre année, sauf environnement de travail très très merdique.
D’abord, parlons de l’entrée.
Si vous recevez un objet et qu’il vous est impossible de trouver l’encoding, vous pouvez forcer un décodage imparfait avec decode()
en spécifiant le paramètre error
.
Il peut prendre les valeurs suivantes :
'strict'
: lever une exception en cas d’erreur. C’est le comportement par défaut.'ignore'
: tout caractère qui provoque une erreur est ignoré.'replace'
: tout caractère qui provoque une erreur est remplacé par un point d’interrogation.
>>> print 'Père Noël'.decode('ascii') Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 1: ordinal not in range(128) >>> print 'Père Noël'.decode('ascii', errors='ignore') Pre Nol >>> print 'Père Noël'.decode('ascii', errors='replace') P��re No��l |
Mozilla vient également à la rescousse avec sa lib chardet qu’il faut donc installer :
pip install chardet |
Et qui TENTE (du verbe ‘tenter’, “qui essaye”, et qui donc peut échouer et se tromper) de détecter l’encoding utilisé.
>>> chardet.detect(u'Le Père Noël est une ordure'.encode('utf8')) {'confidence': 0.8063275188616134, 'encoding': 'ISO-8859-2'} >>> chardet.detect(u"Le Père Noël est une ordure j'ai dis enculé".encode('utf8')) {'confidence': 0.87625, 'encoding': 'utf-8'} |
Cela marche pas trop mal, mais n’attendez pas de miracles. Plus il y a de texte, plus c’est précis, et plus le paramètre confidence
est proche de 1.
Parlons maintenant de la sortie, c’est à dire le cas où le système qui va recevoir vos données est une grosse quiche qui plante dès qu’on lui donne autre chose que de l’ASCII.
Je ne veux balancer personne, mais mon regard se tourne vers l’administration américaine. Subtilement. De manière insistante.
D’abord, encode()
accepte les mêmes valeurs pour errors
que decode()
. Mais en prime, il accepte 'xmlcharrefreplace'
, très pratique pour les fichiers XML :
>>> u"Et là-bas, tu vois, c'est la coulée du grand bronze".encode('ascii', errors='xmlcharrefreplace') "Et là-bas, tu vois, c'est la coulée du grand bronze" |
Enfin, on peut essayer d’obtenir un texte potable en remplaçant les caractères spéciaux par leur équivalent ASCII le plus proche.
Avec l’alphabet latin, c’est très facile :
>>> unicodedata.normalize('NFKD', u"éçûö").encode('ascii', 'ignore') 'ecuo' |
Pour des trucs plus avancés comme le cyrilique ou le mandarin, il faut installer unidecode :
pip install unidecode |
>>> from unidecode import unidecode >>> print unidecode(u"En russe, Moscou s'écrit Москва") En russe, Moscou s'ecrit Moskva |
Merci, merci, merci, et…MERCI.
Ta statue sera équestre. Pas moins.
Fait gaffe aux nombres de pieds en l’air pour le cheval. J’ai pas envie qu’on me prenne pour un macabé.
Pour la matière, le bronze est mon meilleur profile.
s/et le jour où ça se gatte/et le jour où ça se gâte
s/à ou d’autres langage/à où d’autres langages
s/Et certains on plusieurs noms/Et certains ont plusieurs noms
s/c’est ce qu’on appelles les encodings/c’est ce qu’on appelle les encodings
s/Certaines bibliothèque /Certaines bibliothèques
Le sodomiseur de coléoptères :-)
Merci pour l’article, je pensais pas trop mal connaître le sujet, mais visiblement non.
Bah tu sais moi je me dis après chaque article que j’ai bien tout relu et qu’il reste pas de faute. Mais visiblement non.
Franchement merci.
Pour avoir lu plein de choses sur le sujet, mal compris, confondu le vocabulaire, oublié le lendemain, etc… c’est l’article qui explique le mieux et le plus concrètement l’encoding. C’est de la même veine que les articles sur la programmation orientée objet qui sont d’un niveau pédagogique inégalé parmis tout ce que j’ai pu lire. La théorie et les bases sont parfaitement expliquées avec toujours une application concrète. C’est limpide et efficace.
Cela fait un petit moment que je suis régulièrement votre blog, c’est une petite pépite, donc bravo et surtout un grand merci pour le partage car mine du rien c’est du boulot.
\ o /
Yeah, ça part dans mes favoris ! Merci pour l’article !
Premier commentaire constructif de la journée :
Vous avez déjà utilisé cette image d’entête d’article pour un autre article, c’est trop nul, vous perdez votre originalité.
<3
Meeeeeeeeeeeeerde, j’ai eu un doute en plus.
EDIT: m’en fout, je l’ai changé.
Sinon plus sérieusement … c’est un peu perturbant, vous parlez un peu des différences avec Python3 mais la majorité des exemples sont en Python2 et vu que les différences entre python2 et 3 (à ce niveau là en tout cas) sont super chiantes et prêtent à confusion, bah du coup c’est un peu plus dur de bien vous suivre partout (moi qui suis 100% Python3), dommage … Article bien complet sinon :) Merci.
Ah et si l’un de vous à une solution simple pour faire en sorte que les encodings de stdout et stdin se mettent en UTF-8 par défaut, ça serait pas mal. (Surtout que ce sont des propriétés en read only donc, à part des méthodes bizarroïde au lancement de Python (en console), je ne sais même pas si y a moyen de les modifier en live).
Au fait,
je veuxj’aurais bien voulu un tampon :( (tout ça pour ça bitch !)le tampon ça se mérite jeune homme ! N’est pas tamponné qui veut.
@JeromeJ: pour Python3, c’est pareil, exactement le même article sauf que:
– le type ‘unicode’ est appelé ‘str’ et est celui créé par défaut quand on fabrique une chaîne
– le type décodé est appelé ‘byte’
– pas besoin de déclarer “# -*- coding: utf-8 -*-” si ton fichier est en UTF8 car c’est maintenant la valeur par defaut
C’est tout. Tout le reste est pareil.
Quand à s’assurer que toute écriture sur sdtout est en UTF8, c’est sans doute possible en faisant un truc du genre :
Mais je ne le recommanderais pas car :
– ça remplace stout pour tout le code, y compris les libs tierces parties et qui sait ce que ça peut provoquer
– ça rend le code importable (stdout n’est pas en utf8 sous windows, et ça printera un truc illisible)
– ton script peut changer de context en cours d’éxécution, et sdtout ne sera alors plus le même, avec potentiellement un encoding différent
D’une manière générale il vaut mieux spécifier l’encoding par défaut directement sur les fonctions qui font l’opération d’écriture. Par exemple:
Une alternative est de setter la bonne variable d’environnement pour que Python remplisse stdout avec l’encoding que l’on souhaite. Par exemple sous Ubuntu :
http://drj11.wordpress.com/2007/05/14/python-how-is-sysstdoutencoding-chosen/
(ou PYTHONIOENCODING=utf-8:surrogateescape python somescript.py selon les versions)
Cela conditionne par ailleur le résultat de :
@Max: J’aurais essayé !
@Sam: Bien ce que je craignais … Pas mal l’idée de wrapper print avec functools.partial, j’aime !
(C’est bien le prob c’est que je travaille à moitié sous Windows)
Le terminal de windows n’est pas configuré pour afficher de l’UTF8, Python ne pourra rien y changer. Il faut soit y printer l’encoding qu’il utilise actuellement (et se limiter aux caractères qu’il accepte du coup). On peut le trouver en faisant (il me semble):
Mais print devrait se charger de le faire automatiquement en Python3 donc ça devrait pas poser de problème. Simplement tu oublis les caractères chinois.
Soit setter l’encoding avant avec une commande :
http://stackoverflow.com/questions/388490/unicode-characters-in-windows-command-line-how
Ce n’est pas particulièrement lié à Python, c’est pareil dans tous les langages sous Windows car cet OS n’a pas adopté utf8 par default.
“Par défaut, Python plante sur les erreurs d’encoding là ou d’autres langage (comme le PHP) se débrouillent pour vous sortir un truc (qui ne veut rien dire, qui peut corrompre toute votre base de données, mais qui ne plante pas).”
Ouais… bah vaut mieux que ça plante, au moins ça donne l’occasion de réparer proprement.
Merci pour cet excellent résumé.
Il y a encore des choses plus rigolotes à faire avec l’encoding. Par exemple ce fichier est tout à fait valide :
# -*- coding: rot13 -*-
cevag h'Obawbhe fnz'
j’avais découvert ça il y a quelques temps sur linuxfr, avec même en prime l’encodage en brainfuck, mais on peut également imaginer encoder son fichier en whitespace ou tout autre encodage hyper pratique …
Tristement, ça ne marche plus avec Python 3. On pouvait aussi utiliser base64, zlib, etc.
Uhu : http://sebsauvage.net/links/?Q3zlyg
Coïncidence ?
C’est la première fois que j’ai l’espoir de comprendre et d’utiliser correctement les fichues chaînes de caractère en python. Chapeau les mecs ! Mais je flippe quand même de modifier mon code sur ce sujet, qui fonctionne actuellement à peu près.
Par rapport à codec.open, il y a ça dans la doc :
Ça peut être emmerdant ça ? Il y a un moyen simple de faire la conversion à la main ?
Je dirais qu’un bon strip() fera bien l’affaire :-)
En effet, ça marche bien à la lecture, mais du coup pas à l’écriture. Y’a plus qu’à utiliser la version standard sans oublier de convertir, j’ai l’impression.
Autre différence python2/3 : les exceptions. En python3 on peut leur passer un message en unicode, alors qu’en python2 il faut le .encode(“utf-8). Et ça chie avec les docstrings, après…
Bel article, bravo, j’aime bien la structuration en entrée (eh eh les entrées, règle #4, plat (le traitement python), dessert (les sorties, règle #5).
Cependant je vois souvent comme directivepython, les 2 écritures pour UTF8:
# -*- coding: utf8 -*-
ou
# -*- coding: utf-8 -*-
Est-ce la même chose ? Laquelle est à privilégiée ?
C’est kif kif.
Copié collé direct dans mes notes, à côté de : http://sebsauvage.net/python/charsets_et_encoding.html
Merc p〇ʋr cごt art%cle tr⁋s instrucⁱf !
stdin et pas stding dans :
sys.(stding|stdout).encoding.
A part çà, rien à redire, c’est nickel comme d’hab !
C’est l’acceng, c’est pour ça.
Alors là, très bon article !
Quelque soit le langage, le problème le plus récurrent est toujours celui de la manipulation des différents types d’encoding.
Je ne te parle pas de ceux qui développent sous Windows avec un CP-1252 par défaut dans tous les logiciels et qui même avec un réglage de l’IDE finit un jour où l’autre par te ressortir l’encoding par défaut genre .. à la réouverture.
Bref, éternel problème que tu as très bien mis en évidence. Tout le problème est d’origine interface chaise-clavier. Il faut se sortir les doigts du boule pour faire du propre.
Juste merci
Merci grandement!
2 jours que je plante sur ces %?!/%££!! d’encoding, et en 15 minutes… Réglé
Thanx
Continue!!!
C’est laborieux chez leaseweb :/
Ensuite ça a été un probleme de varnish qui s’est bien lancé quand leaseweb a reboot les VPS mais qui pour une raison mystérieuse ne voulait rien savoir :/
Merci pour l’article qui m’a bien aidé sur certains points de blocage mais il y a toujours quelque chose que je ne parviens pas à résoudre : le parsing (avec os.walk) de fichiers qui contiennent des accents. Ce qui me déroute surtout c’est la différence entre Windows et Ubuntu.
Dans mon programme j’ai une fonction (li_geofiles()) chargée de lister les fichiers compatibles (selon leur extension et l’existence de leurs dépendances) contenus dans une arborescence à partir d’un dossier indiqué par l’utilisateur (foldertarget retourné via tkMessageBox.askdirectory) et qui bloque sur les noms de fichiers qui contiennent un accent…mais seulement sur Ubuntu ! Ça fait 2 jours que je me flagelle là-dessus et j’ai essayé qqls solutions :
– un try/except sur le nom de fichier et réencodage à la volée (solution choisie) mais qui a le (gros) défaut de ne pas lister les fichiers avec accents (os.path.isfile ne les reconnaît pas…)
– passer foldertarget en unicode mais ça marche pô (idem avec path.normpath(foldertarget)
Voici la fonction en question :
Si quelqu’un voit le problème…et surtout la solution !
PS : je suis géographe à la base donc pas vraiment un développeur… #indulgence
Un grand merci, enfin un tuto qui va à l’essentiel. J’ai enfin compris comment ça fonctionne.
Juste au Top!
Un super cadeau de Noel qui vient de m’offrir une ou deux nuit planche de moins
Article auquel je me réfère régulièrement, car à chaque fois que je résout mes problèmes d’encodage, je ne me souviens plus comment je les ais résolus et je dois refaire le raisonnement dans mon cerveau.
Juste pour info : y’a des fois, syt.stdout.encoding renvoie None.
Je suis en python 2.7 sous Windows (oui, je sais), quand j’exécute mon script dans la console, j’ai “cp850″. Quand je l’exécute avec Ctrl-B dans Sublime Text, j’ai None.
Du coup, je fais le bourrin comme ça pour écrire sur stdout :
Cela va sans dire, mais je précise que dans mon code précédent, j’ai bien évidemment mis le “from __future__ import unicode_literals” au début de mes fichiers.
Du coup la chaîne “é mon cul cé du poulé” est de l’unicode.
Et ça marche, je vois mes accents, aussi bien dans la console DOS que dans la console Sublime Text.
Article salvateur!
Juste une question:
os.mkdir(stringenutf8.encode(sys.getfilesystemencoding())) ne marche pas sur windows avec python 2.7
Tu sais pourquoi?
Parce qu’il y a plusieurs notions mélangées dans cette ligne.
mkdir a besoin d’une chaîne encodée dans l’encoding du file system.
stringenutf8 est visiblement déjà encodée. On ne peut pas appelée “encode()” dessus.
Soit l’encoding du fs est utf8, auquel cas tu peux l’utiliser directement, soit il faut décoder la string vers unicode, et la réencoder vers l’encoding du fs.
tu m’as sauvé la vie, 1 semaine à me battre sur un code car un pu### de “°” dans l’adresse !!
bref, je te vénère. Merci pour cet excellent article en VF.
ps : j’aime bien l’exemple str(“Détécé”) …
Une petite chose qui me semble avoir été omise dans l’explication, c’est que utf-8 est compatible avec ascii.
C’est à dire que les 128 premiers caractères de la table utf-8 correspondent à la table ascii (c’est d’ailleurs une des raisons pour laquelle utf-8 est utilisé aux détriments des autres unicodes qui sont utf-16 et utf-32).
Je retombe dessus ; toujours très bon, comme d’habitude.
J’en profite pour corriger quelques typos :
Le texte sera de type ‘str’, et decode() retourne (si vous lui fournissez le bon codec ;-)), une version ‘unicode’.
-> soit virer la virgule, soit changer les parenthèses en virgules.
un envoie dans une socket
-> envoi
A la sortie
-> À
Les outils de la dernières chance
-> dernière
cyrilique
-> cyrillique
Merci à vous et continuez en restant comme vous êtes.
Il eut été plaisant que je commençasse à lire ce blog il y a quelques mois, avant de décider d’apprendre ruby&rails.
C’est fou ce que python ressemble à ruby, soit dit en passant.
Peut être un chouilla moins élégant, mais moins tortueux à relire quand on connaît pas…la preuve j’arrive à comprendre presque tout sans faire trop d’efforts.
Given I’am as bright as a dark night…excellents articles très bien rédigés. Un grand merci.
@Goldy merci pour la précision, ça me chiffonnait justement.
@Goldy: j’étais persuadé de l’avoir mis, je deviens gaga.
Vrabo
Disons tous en choeur : “àéèùçÀÉÈÙÇ” – non : en chœur, c’est quand même plus joli…
Dans python3, on peut passer un encoding à la fonction open(), le décodage se fera de manière transparente. Super pratique !
C’est possible en python2 avec le module coding, mais celui-ci, ne gère pas les différentes fin de ligne, ce qui est bof pour un truc sensé être plus compatible.
bonjour,
si par exemple je telecharge la page de google qui est securisé et ya du sharabiaya dans le code source et qui est en binaire comment faire pour convertir en utf-8 sachant que j’ai une erreur de conversion quand j’essai et puis comment faire pour lire les vrai contenue par exemple les resulats des recherche avec les liens et non le charabiya de truc securisé
Je ne connais aucune page de google sécursé avec un code source en binaire.
Quand je vais sur google.com, je vois bien le code source :
http://0bin.net/paste/9-wDHADDZvekQFyC#G1VToTRNQslSE7ZaWWYI1eAK5l8k1sEjNyaFWej+DfQ=
C’est beaucoup de javascript compressé, mais c’est un code source en clair.
Le charset n’est pas déclaré dans la page, mais par les headers :
Donc c’est bien de l’utf8.
Obtenir les résultats de la recherche plutôt que le code n’a rien à voir avec cela. Ce n’est pas une question d’encoding, ni de binaire, c’est simplement le niveau de fonctionalité que google choisit d’utiliser en fonction du client. Si tu te fais passer pour lynx par exemple, google n’utilisera pas javascript et tu récupéreras du HTML pure, plus facile à parser. Par exemple, avec la lib requets :
Et ça me file du HTML que je peux lire avec beautifulsoup.
Bonjour,
je cherche à lire le fichier dump windows et rien à faire, avez-vous une idée merci
Il faut manger des crêpes au chocolat. Tout va mieux avec des crêpes au chocolat.
Parfait cet article pour se dépatouiller quand on y comprend queudal :).
Merci pour ce gros travail. En 20 minutes de lecture, ce blog me fait gagner à chaque fois minimum 2h. Faudrait que j’vous verse une partie de mon salaire…
Petit détail concernant l’article : Perso, j’ai du mal avec la notion d’encode et de decode (dans quel sens est-ce que ça marche), puisque finalement le texte de brute n’existe pas comme c’est dit, à quoi correspondent les données que l’on a de part et d’autre d’une chaine str ou byte (pas simple de se faire comprendre, bref).
J’ai trouvé des éléments de réponses dans un article détaillé de la doc python : https://docs.python.org/3/howto/unicode.html (Existe aussi pour python 2)
Le texte est un flux de bits. Ce flux de bits est dans un encoding. Quand on décode, on récupère un objet python qui peut être traduit vers n’importe quel autre flux de bits. Ce qu’il y dans cet objet Python n’est pas important. Il faut imaginer qu’il est neutre. Decoder fait passer du flux de bits à cet objet Python, encoder fait passer de cet objet python aux flux de bits.
Merci d’avoir pris le temps de répondre, la doc python m’avait fait comprendre quelque chose de ce genre, mais là c’est très clair :).
Merci pour cet article clair et utile.
Petit bémol à l’article : “En Python 2.7, l’encoding par défaut est ASCII, donc il faut presque toujours le déclarer”
Oui, il faut le déclarer si on souhaite coder autrement qu’en ascii, et dans ce cas, ça revient à dire “si on souhaite coder des strings autre qu’en ascii”. Autre précision qu’il ne me semble pas avoir lu : UTF8 est compatible ASCII (pas le contraire évidemment). Donc, un code 2.7 codé/enregistré en ascii est compatible avec un interpréteur 3.x. Enfin, l’encoding sqlite3 par défaut est l’utf8 (pragma encoding), ce qui lui confère également une compatiblité totale avec du code 2.7 en ascii (et autre création de table ou injection de données interne au programme).
Et pour terminer : “régler son éditeur sur le bon encoding” : oui et non : vim va régler l’encoding par défaut sur le “locale” en cours (:set encoding=…) ; mais, si on code en C ou en Python, un :w écrira bien le fichier en ascii à moins d’utiliser des caractères non ascii propre au “locale” en cours (éè …). Eclipse travaille de la même façon, je peux avoir un “locale” en latin-1 (iso8859-1), coder sous PyDev ou CDT, le résultat sera bien un fichier ascii. Mes 2 kopecs. Merci pour l’article. cdt,
J’essai un peu le langage python sur l’ide netbeans, franchement pas convaincu… la doc existe en français ? (mais c pas sûr d’y comprendre d’avantage).
Kel bordel l’encoding, j’arrive jamais à savoir kel encode y faut utiliser mais dans netbeans, tou s’affiche bien (lequel utilise par défaut windows-1252). dans la console y’a pas un accent qui s’affiche correc. jamais vu un langage aussi ambigue et confus… chiotte !
J’ai jamais vu de doc en fr.
Pour ton encoding, il faut que tu relise l’article. Il te faut connaitre l’encoding de ta console, comme pour tous les langages du monde.
Bon, ok, j’ai fini par comprendre un peu mieux le sujet et comment Python s’est adapté à la norme Unicode. J’ai surtout compris qu’à force de fouiller un string on finit par découvrir qu’il est en fait constitué de Bytes lesquels on des possibilités de “petits” ou “gros bouts” selon les types utf-16 BE et LE ?
Cela dit, le comportement du code n’a pas les mêmes répercussions depuis la console de Netbeans ou exécuté par le fichier sur le desktop. Dans l’interpréteur Python, j’ai bien les caractères accentués qd varText.decode(‘utf-8′). La même instruction dans la console de l’IDE léve une erreur:
AttributeError: ‘str’ object has no attribute ‘decode’
Sauf si VarText =’chaine’.encode(‘utf-8′) à été auparavant formulé. Donc, ça roule qd même pas mal mais faut bien comprendre quel type d’objet est restitué dans les manip.
Il y a une différence fondamentale entre Python 2 et 3, et selon que tu manipule une chaîne ou des bytes. Et bien entendu, il y a une différence entre l’encoding de ton IDE, celui de la console de l’IDE, et celui de la console de l’OS.
Encore une fois, relis l’article. Il te faut ces informations pour répondre à ta question.
Ce n’est pas spécifique à Python, il faut connaitre l’encoding dans tous les langages du mondes.
Ok pour l’encoding, qu’en est-il de la charmap de Python ?
print(‘\u0100′)
UnicodeEncodeError: ‘charmap’ codec can’t encode character ‘\u0100′ in position 0: character maps to
Pourquoi Python ne trouve pas un point de codage dans la table Utf-8 ?
Ce n’est pas que Python ne trouve pas le point de codage dans la table UTF8, c’est que ce caractère n’existe pas dans l’encodage de sortie. Tu essayes de faire passer un cube dans un trou rond.
Si tu affiche ce caractère dans une console supportant l’UTF8, ça marche parfaitement.
Je me répète donc pour la 3eme fois, relis l’article car tu n’as récupéré aucune des informations que je souligne comme étant indispensables à avoir.
Tu ne m’as jamais donné ton OS. Ni ta version de Python. Ni quelle était ta sortie et son encoding.
Effectivement ça manque d’infos, je suis sur W7-64 et j’utilise Python33.
Apparemment le pluggin Python pour Netbeans développé par le support Oracle comporte un bug. J’ai contacté le support pour avoir des infos et comment résoudre ça, j’attend la réponse.
Je crois devoir chercher un autre IDE pour le dév en Python.
Re, j’insiste encore, quitte à devenir un peu lourd, j’ai beau relire l’article, je ne vois nulle part le principal intéressé…
On est bien d’accord que l’encoding sert à transformer une grille de chose d’une matrice sur une autre, au final c’est ce que ça fait, découvrir où sont placés des éléments dans un tableau…
Ici les éléments en question sont des signes typographiques, lesquels plus globalement sont des dessins appelés glyphes.
Nulle part cet article n’explique comment ces glyphes peuvent s’afficher sur un écran … nulle part ni Unicode ni les grilles UTF-8 n’indique comment dessiner sur un écran ces glyphes.
Je n’ai pas été assez précis sur la nature des erreurs rencontrés certes, mais bien souvent il n’y a simplement rien ou bien juste des carrés qui s’affichent pour remplacer les glyphes. Ça veut dire que l’encoding fonctionne mais l’affichage est incapable de produire le glyphes correspondant.
En changeant la police d’Output par défaut de l’IDE (Arial MS Unicode), les caractères à présent s’affiche correctement.
CQFD. Peut être sur d’autres terminaux cette substitution de caractères est automatique mais en l’occurrence Netbeans avec le pluggin Python ne la produit pas. Au moins ça aura servit à clarifier ce point non négligeable.
Ah, mais ça n’a rien à voir avec Python ça, c’est juste que tu utilises des polices qui n’ont pas les glyphes en UTF8. Imagines si chaque articles doit répondre à toutes les config, on est pas rendu…
Oui, c’est vrai que c’est parallèle au sujet…
Autre question: j’essaie de changer l’encoding de sortie qui semble boulonné à l’objet STDOUT.
En parcourant Stackoverflow il y a une flopée de post sur ce sujet mais pas de réponse ouvrant sur une modif de la config.
Toujours en Python 3.x sous W7 64, voilà les données:
print(sys.getdefaultencoding()) →UTF-8
print(locale.getpreferredencoding()) →cp1252
Je comprend pourquoi alors que tout est UTF-8, je n’arrive pas à mettre le STDOUT de même. Une solution à été formulé, elle fonctionne et c’est la plus courte observé:
utf8stdout = open(1, 'w', encoding='utf-8', closefd=False)
# fd 1 is stdout
print(everyfile, file=utf8stdout)
Avec ça effectivement il n’y a plus d’erreur de charmap mais bon c’est juste un hack, y’a pas une soluce plus propre ?
Mettre le sdtout en en UTF8 ne veut rien dire. Sdtout est juste un objet qui représente la sortie standard.
Python n’a aucun contrôle sur le périphérique de sortie. Si le périphérique ne supporte pas l’encoding donné, on ne peut pas l’utiliser. C’est aussi simple que ça. On ne peut pas afficher des caractères UTF8 sur une console qui ne supporte pas l’UTF8. Avec aucun langage du monde. Ce n’est pas particulièrement lié à Python.
Vu que je ne sais toujours pas ce que vous voulez faire car vous ne l’avez toujours pas écris, je n’ai aucun moyen de vous aider. De surcroit, les commentaires de blog sont très mal adaptés à l’aide des gens en ligne.
Mon conseil :
– relisez l’article (bis, ter, etc). Vous avez visiblement raté des choses importantes.
– suivez les conseils des choses à lister pour s’en sortir avec l’encoding. Après autant de message et autant d’appel de ma part à relire l’article, vous n’avez TOUJOURS PAS listé l’encoding de votre sortie ni précisé si votre texte était uniquement issu de strings du code où d’une autre source.
– rédigez votre message de demande d’aide en suivant ce template : http://sametmax.com/template-de-demande-daide-en-informatique/. Vraiment, jouer au chat et à la souris pour récupérer des bouts d’indices pour aider quelqu’un qui programme à rédiger une demande d’aide décente, c’est fatiguant.
– postez le dit message sur un forum.
Je pense comprendre votre problème, mais vous ne me facilitez pas la tâche pour le résoudre. Je m’arrête donc là.
Merci…
au delà du fait de la qualité de l’article.
Il exprime mon état de nerf face à ce p***** de problème d’encoding entre 2 PC avec 2 versions de windows et 2 versions de python qui essaient de communiquer ensemble. (oui, j’aime me faire du mal…”foooouettez-moi bien fort, maîtresse!!”
Superbe article.
Il m’a beaucoup éclairé sur le sujet.
Vraiment merci pour le tuto. Cela fait plus de 3 semaines que je galère avec cette histoire d’ encodage. Probleme enfin resolu. Merci vraiment.
Une explication complète de A à Z pour éviter la migraine :-)
Merci beaucoup
Excellent! Merci pour cette synthèse appréciée, je partage.
Pourquoi avoir préfixé d’un “u” la chaîne dans
msg = u"Page '{}' sauvée\n".format(nom)
alors que tu importé unicode_literals ?La force de l’habitude. Ca n’a aucune impact.
Bonsoir, python, c’est tout nouveau pour moi désolé si je dis des bêtises …
j’vu dans les commentaire qu’une autre personne a rencontré le même que moi, à savoir le problème dees noms de fichiers avec des accents lorsque que l’on utilise walk pour parcourir une arboresence. Je ne pense pas avoir vu de solution où de suggestion …
l’un de vouspurrait-il m’aider ?
Avant d’oublier, merci pour cette synthèse très pratique.
A bientôt et bonnes fêtes de fin d’année à tout le monde.
Pwalkour
En pyhton 2.7 :
Donc les chemins sont de types bytes, et il faut décoder, comme indiquer dans l’article.
Donc les chemins sont de types unicode, et il n’y a rien à faire.
Si tu lis l’article, tu sauras exactement quoi faire avec ces informations, il n’y a rien de magique.
Bonjour à tous,
les recherches pour un soucis avec python m’ont amené ici, alors je me disais que peut être trouverais-je la solution au problème.
J’utilise depuis quelques temps mps-youtube, petit outils fort sympathique je dois dire.
Mais depuis une mise à niveau rien ne va plus, il me sort une erreur tel que celle exposée ici…
donc j’installe:
sudo pip install mps-youtube
puis je lance le soft :
mpsyt
j’envoie une recherche,
.pantera
je lui demande les infos d’une vidéo
d2
ensuite je demande le téléchargement, c’est là que l’erreur se présente :
10
mps-youtube a écrit :
Problem playing last item: 'ascii' codec can't decode byte 0xc3 in position 13: ordinal not in range(128)
Que puis-je faire ?
Ta question n’est pas vraiment lié à l’article car tu ne programmes pas, mais utilise le logiciel, donc le mieux c’est que tu la pose ici : indexerror.net.
Bonjour, j’essaye d’envoyer des séquences d’échappement à une imprimante HP en réseau (python 2.7 sous Windows, ‘cp850′ pour stdout et ‘mbcs’ pour le système de fichier ).
J’ai essayé de fixer mes problème d’encoding en lisant l’article et fait des gros gros gros efforts (voir code ci-dessous) pour bosser en unicode!
Si je tape le tout en python interactif, cela marche a moitier (mais séquences d’échappement sont ignorées… tout ce qui est événtuellement lisible est imprimer… comme @PJL JOB NAME =)
Le plus étrange, si j’exécute script avec python script.py j’ai l’erreur d’encodage suivante (le script est pourtant sauvé en utf8 par l’éditeur PSPAD).
Traceback (most recent call last):
File “hp-minimal-job.py”, line 55, in
do_simple_pcl_print_job()
File “hp-minimal-job.py”, line 45, in do_simple_pcl_print_job
print (u”.join( l )) #.encode( sys.stdout.encoding )
File “C:\Python27\lib\encodings\cp850.py”, line 12, in encode
return codecs.charmap_encode(input,errors,encoding_map)
UnicodeEncodeError: ‘charmap’ codec can’t encode character u’\u2013′ in position
2: character maps to
Qu’est ce que j’ai bien pu raté?
——————- LE SCRIPT ——————————————–
!/usr/bin/env python
-- coding: utf8 --
import socket
import sys
HP Network Printer Connexion Point
PRINTER_IP = ‘192.168.1.206’
PRINTER_PORT = 9100
PJL is used to manage the job and encapsulate a PCL page
PCL is the content to be printer.
#
def pjl_escape( cmd ):
“”” Prepare an escaped command string with cmd as command content “””
return u”+chr(27)+cmd
def pjl_eol():
“”” return the pjl Enf-of-Line composed of space+cr+lf “””
return u’ ‘+chr(13)+chr(10)
def prepare_pjl_job( jobname ):
“”” initiable a PJL job + switch to PCL language “””
l = [] # prepare list of string
l.append( pjl_escape(u’%–12345x’)+str(u’@PJL JOB NAME = “‘)+jobname+str(u'”‘)+pjl_eol() )
l.append( u’@PJL ENTER LANGUAGE = PCL’+pjl_eol() )
return u”.join(l)
def close_pjl_job():
return pjl_escape(u’%–12345x’)+str(u’ @PJL EOF’)+pjl_eol()+pjl_escape(u’%–12345x’)
def do_simple_pcl_print_job():
s = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
s.connect( (PRINTER_IP, PRINTER_PORT) )
l = []
l.append( prepare_pjl_job(u”invoice x customer y”) )
l.append( u’Essai d impression é@ testing’ ) # PCL command here
l.append( close_pjl_job() )
A imprimer
print (u”.join( l )) #.encode( sys.stdout.encoding )
for c in (u”.join( l ))[0:-1]:
print( (‘%03i ‘ % ord(c)).encode( sys.stdout.encoding) )
Envoyer à l’imprimante
s.sendall( (u”.join(l)).encode( ‘cp850′ ) ) # Ne pas envoyer le dernier caractère qui est un NULL
s.close()
if name == ‘main‘:
do_simple_pcl_print_job()
Bonjour dominique,
Pose ta question ici : indexerror.net
putain merci !
Il faudrait toutefois clarifier ce que demande python3, parce que dire que c’est de l’ Unicode par défaut n’est pas suffisant.
Unicode est un standard et une norme. C’est tout.
UTF décrit une “transformation” qui répond au standard Unicode et UTF-8 en est le pendant codé sur 8bits.
Par contre, préfixer les chaines avec un “u” correspond en général à déclarer une chaine de caractères codée en UTF-8.
Donc quel est l’encodage par défaut d’un compilateur python3 ? Sachant que dans le monde Windows, le terme ‘Unicode’ est mal employé pour désigner de l’UTF-16(*) alors que dans le monde Unix, il est tout aussi mal employé pour désigner de l’ UTF-8 …
D’autant que le compilateur ou l’interpréteur peut lire un fichier dans un encodage et en utiliser un autre en interne (un pratique courante est de lire de l’utf-8 ou du latin-1 par défaut – voire exclusivement- et de stocker les chaines en UTF-16 )
Ce qui d’ailleurs enfonce le clou pour affirmer que l’encodage doit être précisé et ne doit jamais être “supposé” par défaut…
(*): pire encore, il y a deux UTF-16 (selon l’ endianess) et je ne sais pas lequel est utilisé en interne sous Windows.
Salut et merci pour l’article!
J’ai relevé une mini erreur pour la déclaration d’encoding du fichier : # -- coding: utf8 --
Après essai python2.7 retourne une erreur car c’est : # -- coding: utf-8 --
C’est tout, simple correction de mini coquille :)
Good night
Hum, normalement ce sont des alias, et les deux marchent sur ma machine. Une spécificité windows ? A creuser.
Oh *;:@\#% de *;:@\#% ! L’article que je cherchais depuis 2~3 ans !
Une nouvelle ère s’ouvre pour moi désormais.
Merci
“Je sais une chose : c’est que j’étais aveugle, maintenant je vois” Jean IX.25
J’adore le thon employé sur ce site (c’est pas une faute au niveau cul ;-)))
Dans le genre branlette, je suis tombé sur (je parle d’accent en l’occurrence)
sur la différence entre les accents composés et les accents décomposés (même moi je n’y ai pas cru)
Genre un ë et un ë voire un è et un è, ça saute pas à l’œil mais il y’a plusieurs manières de le faire, vu le niveau
des agitateurs je me dis, et vu l’article que je viens de lire (c’est bon les gars, respect :-))
Si ça continue je file élever des chèvres dans le Larzac ;-)
(et comme disais @Coluche il n’y a pas de meeeeehhhhh)
Bonjour,
Pouvez vous m’expliquer pourquoi j’obteint systèmatiquement une erreur ? faut-il que j’importe une bibliotèque particulière ?
IDLE 2.6.5 ==== No Subprocess ====
Salut,
Tu devrais poser ta question sur http://indexerror.net, tu auras plus de chance d’avoir une réponse et ça pourra servir à d’autres.
Bon je croyais avoir tous compris mais je tombe sur cet article.
Pourquoi ASCII est dans la liste des encodage alors que c’est suposé etre un jeux de caractère? (qui pourrais etre encodé en utf-8 par exemple)
ASCII et UTF8 sont tous les deux des jeux de caractères (caracter sets). L’encodage (encoding) est le processus qui transforme un jeu de caractères en un autre. Ppour cette raison, on fait , comme dans cet article, souvent l’abus de langage en parlant d'”encoding ASCII” ou “encoding UTF8″ alors qu’on devrait dire “charset ASCII” et “charset UTF8″.
Comme les jeux de caractères ne sont pas équivalent, l’encoding en Python se fait par une forme intermédiaire, vers laquelle on decode() et depuis laquelle on encode(), ce qui permet de facilement identifier quand le processus échoue : au niveau du charset de départ ou de celui d’arrivée. Cela permet aussi d’isoler le texte comme un type à part en Python 3 : str est considéré comme du texte pur, tandis que tout texte encodé est sous forme de bytes.
En vérité, str est implémenté en utilisant utf8. Mais on a pas besoin de le savoir, et cela peut changer. C’est juste une API pour donner :