172 votes

Python, Unicode et la console Windows

Lorsque j'essaie d'imprimer une chaîne Unicode dans une console Windows, j'obtiens une erreur .

UnicodeEncodeError: 'charmap' codec can't encode character ....

Je suppose que c'est parce que la console Windows n'accepte pas les caractères Unicode uniquement. Quelle est la meilleure façon de contourner ce problème ? Existe-t-il un moyen de faire en sorte que Python imprime automatiquement un message de type ? au lieu d'échouer dans cette situation ?

Edit : J'utilise Python 2.5.


Note : La réponse de @LasseV.Karlsen avec la coche est en quelque sorte périmée (de 2008). Veuillez utiliser les solutions/réponses/suggestions ci-dessous avec précaution !

Réponse de @JFSebastian est plus pertinent à partir d'aujourd'hui (6 janvier 2016).

0 votes

Quelle version de Python utilisez-vous ? J'ai vu des références indiquant que ce problème existait dans la version 2.4.3 et qu'il a été corrigé dans la version 2.4.4.

3 votes

0 votes

Vérifier ce dehors.

38voto

Lasse V. Karlsen Points 148037

Note : Cette réponse est en quelque sorte périmée (elle date de 2008). Veuillez utiliser la solution ci-dessous avec précaution !


Voici une page qui détaille le problème et une solution (recherchez le texte dans la page). Envelopper sys.stdout dans une instance ) :

PrintFails - Python Wiki

Voici un extrait de code de cette page :

$ python -c 'import sys, codecs, locale; print sys.stdout.encoding; \
    sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout); \
    line = u"\u0411\n"; print type(line), len(line); \
    sys.stdout.write(line); print line'
  UTF-8
  <type 'unicode'> 2

  $ python -c 'import sys, codecs, locale; print sys.stdout.encoding; \
    sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout); \
    line = u"\u0411\n"; print type(line), len(line); \
    sys.stdout.write(line); print line' | cat
  None
  <type 'unicode'> 2

Vous trouverez de plus amples informations sur cette page, qui vaut la peine d'être lue.

8 votes

Le lien est mort et l'essentiel de la réponse n'a pas été cité. -1

1 votes

Quand j'essaie les conseils donnés pour emballer sys.stdout il imprime les mauvaises choses. Par exemple, u'\u2013' devient û au lieu d'un en-dash.

0 votes

@user2357112 Vous devrez poster une nouvelle question à ce sujet. Unicode et console système ne sont pas nécessairement la meilleure combinaison, mais je n'en sais pas assez à ce sujet, donc si vous avez besoin d'une réponse définitive, posez une question à ce sujet ici sur SO.

31voto

Daira Hopwood Points 687

En dépit des autres réponses plausibles qui suggèrent de changer la page de code en 65001, cela ne fonctionne pas . (De même, la modification de l'encodage par défaut à l'aide de sys.setdefaultencoding es pas une bonne idée .)

Ver cette question pour les détails et le code qui fonctionne.

2 votes

win-unicode-console Le paquetage Python (basé sur votre code) permet d'éviter de modifier votre script s'il imprime directement l'Unicode à l'aide de py -mrun your_script.py commande .

12voto

Giampaolo Rodolà Points 2965

Si vous n'êtes pas intéressé par l'obtention d'une représentation fiable du ou des mauvais caractères, vous pouvez utiliser quelque chose comme ceci (fonctionne avec python >= 2.6, y compris 3.x) :

from __future__ import print_function
import sys

def safeprint(s):
    try:
        print(s)
    except UnicodeEncodeError:
        if sys.version_info >= (3,):
            print(s.encode('utf8').decode(sys.stdout.encoding))
        else:
            print(s.encode('utf8'))

safeprint(u"\N{EM DASH}")

Le ou les mauvais caractères de la chaîne seront convertis en une représentation imprimable par la console Windows.

0 votes

.encode('utf8').decode(sys.stdout.encoding) conduit à mojibake, par exemple, u"\N{EM DASH}".encode('utf-8').decode('cp437') -> Çö

0 votes

Tout simplement print(s.encode('utf-8')) peut être un meilleur moyen d'éviter les erreurs de compilation. Au lieu de cela, vous obtenez \xNN pour les caractères non imprimables, ce qui était suffisant pour mes messages de diagnostic.

6 votes

C'est énorme, spectaculairement mauvais. L'encodage en UTF-8 puis le décodage en tant que jeu de caractères 8 bits a) échouera souvent, car tous les codepages n'ont pas de caractères pour toutes les valeurs de 256 octets, et b) toujours l'interprétation erronée des données, produisant un Mojibake à la place.

10voto

sorin Points 23747

Le code ci-dessous permet à Python de sortir sur la console en UTF-8 même sous Windows.

La console affichera bien les caractères sur Windows 7 mais sur Windows XP, elle ne les affichera pas bien, mais au moins cela fonctionnera et surtout vous aurez une sortie cohérente de votre script sur toutes les plateformes. Vous pourrez rediriger la sortie vers un fichier.

Le code ci-dessous a été testé avec Python 2.6 sous Windows.

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import codecs, sys

reload(sys)
sys.setdefaultencoding('utf-8')

print sys.getdefaultencoding()

if sys.platform == 'win32':
    try:
        import win32console 
    except:
        print "Python Win32 Extensions module is required.\n You can download it from https://sourceforge.net/projects/pywin32/ (x86 and x64 builds are available)\n"
        exit(-1)
    # win32console implementation  of SetConsoleCP does not return a value
    # CP_UTF8 = 65001
    win32console.SetConsoleCP(65001)
    if (win32console.GetConsoleCP() != 65001):
        raise Exception ("Cannot set console codepage to 65001 (UTF-8)")
    win32console.SetConsoleOutputCP(65001)
    if (win32console.GetConsoleOutputCP() != 65001):
        raise Exception ("Cannot set console output codepage to 65001 (UTF-8)")

#import sys, codecs
sys.stdout = codecs.getwriter('utf8')(sys.stdout)
sys.stderr = codecs.getwriter('utf8')(sys.stderr)

print "This is an mp testing Unicode support using Arabic, Latin, Cyrillic, Greek, Hebrew and CJK code points.\n"

1 votes

Y a-t-il un moyen d'éviter cela en utilisant une autre console ?

0 votes

@sorin : Pourquoi faites-vous d'abord import win32console en dehors d'un try et plus tard, vous le faites de manière conditionnelle dans un try ? N'est-ce pas un peu inutile (le premier import )

0 votes

Pour ce que ça vaut, celui fourni par David-Sarah Hopwood fonctionne (je n'ai même pas réussi à le faire fonctionner parce que je n'ai pas pris la peine d'installer le module d'extension win32).

1voto

La cause de votre problème est PAS la console Win ne veut pas accepter Unicode (comme elle le fait depuis je suppose Win2k par défaut). C'est l'encodage par défaut du système. Essayez ce code et voyez ce qu'il vous donne :

import sys
sys.getdefaultencoding()

si c'est écrit ascii, c'est que vous avez trouvé la cause ;-) Vous devez créer un fichier appelé sitecustomize.py et le mettre dans le chemin de python (je l'ai mis dans /usr/lib/python2.5/site-packages, mais c'est différent sous Win - c'est c : \python\lib\site -packages ou autre), avec le contenu suivant :

import sys
sys.setdefaultencoding('utf-8')

et peut-être voudrez-vous également spécifier l'encodage dans vos fichiers :

# -*- coding: UTF-8 -*-
import sys,time

Edit : plus d'informations peuvent être trouvées en excellent le livre Dive into Python

3 votes

Setdefaultencoding() n'est plus dans sys (depuis la v2.0 selon la documentation du module).

0 votes

Je ne peux pas le prouver pour le moment, mais je sais que j'ai utilisé cette astuce sur une version ultérieure - 2.5 sous Windows.

6 votes

OK, après un certain temps, j'ai découvert que : "Cette fonction est uniquement destinée à être utilisée par l'implémentation du module site et, le cas échéant, par sitecustomize. Une fois utilisée par le module site, elle est supprimée de l'espace de noms du module sys."

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X