Python, Unicode y la consola de Windows


Cuando intento imprimir una cadena Unicode en una consola de Windows, obtengo un error UnicodeEncodeError: 'charmap' codec can't encode character ..... Asumo que esto se debe a que la consola de Windows no acepta caracteres de solo Unicode. ¿Cuál es la mejor manera de evitar esto? ¿Hay alguna manera de hacer que Python imprima automáticamente un ? en lugar de fallar en esta situación?

Edit: Estoy usando Python 2.5.


Nota: @LasseV.La respuesta de Karlsen con la marca de verificación es algo anticuada (de 2008). Por favor, utilice el soluciones / respuestas / sugerencias a continuación con cuidado!!

@La respuesta jfsebastiana es más relevante a partir de hoy (6 de enero de 2016).

Author: Community, 2008-08-08

13 answers

Nota: Esta respuesta está un poco desactualizada (de 2008). Por favor, utilice la solución a continuación con cuidado!!


Aquí hay una página que detalla el problema y una solución (busque en la página el texto Wrapping sys.stdout en una instancia):

PrintFails-Python Wiki

Aquí hay un extracto de código de esa página:

$ 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
  Б
  Б

Hay más información en esa página, bien vale la pena leerla.

 32
Author: Lasse Vågsæther Karlsen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-04 17:18:53

Actualizar: Python 3.6 implementa PEP 528: Cambiar la codificación de la consola de Windows a UTF-8: la consola predeterminada en Windows ahora aceptará todos los caracteres Unicode. Internamente, utiliza la misma API Unicode que el paquete win-unicode-console mencionado a continuación. print(unicode_string) debería funcionar ahora.


Obtengo un error UnicodeEncodeError: 'charmap' codec can't encode character....

El error significa que los caracteres Unicode que está tratando de imprimir no se pueden representar codificación de caracteres de consola actual (chcp). La página de código es a menudo codificación de 8 bits como cp437 que puede representar sólo ~0x100 caracteres de ~1M caracteres Unicode:

>>> u"\N{EURO SIGN}".encode('cp437')
Traceback (most recent call last):
...
UnicodeEncodeError: 'charmap' codec can't encode character '\u20ac' in position 0:
character maps to 

Asumo que esto se debe a que la consola de Windows no acepta caracteres solo Unicode. ¿Cuál es la mejor manera de evitar esto?

La consola de Windows acepta caracteres Unicode e incluso puede mostrarlos (solo BMP) si la fuente correspondiente está configurada. WriteConsoleW() API debe ser se usa como se sugiere en la respuesta de@Daira Hopwood . Se puede llamar de forma transparente, es decir, no es necesario y no debe modificar sus scripts si utiliza win-unicode-console paquete :

T:\> py -mpip install win-unicode-console
T:\> py -mrun your_script.py

Ver ¿Cuál es el problema con Python 3.4, Unicode, diferentes lenguajes y Windows?

¿Hay alguna manera de que pueda hacer Python imprimir automáticamente un ? en lugar de fallar en esta situación?

Si es suficiente para reemplazar todos los caracteres no codificables con ? en su caso, entonces usted podría establecer PYTHONIOENCODING envvar:

T:\> set PYTHONIOENCODING=:replace
T:\> python3 -c "print(u'[\N{EURO SIGN}]')"
[?]

En Python 3.6+, la codificación especificada por PYTHONIOENCODING envvar se ignora para los buffers de consola interactivos a menos que PYTHONLEGACYWINDOWSIOENCODING envvar se establezca en una cadena no vacía.

 53
Author: jfs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:44

A pesar de las otras respuestas que suenan plausibles que sugieren cambiar la página de códigos a 65001, eso no funciona. (Además, cambiar la codificación predeterminada usando sys.setdefaultencoding es no es una buena idea.)

Vea esta pregunta para detalles y código que funciona.

 25
Author: Daira Hopwood,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:33

Si no está interesado en obtener una representación confiable de los caracteres malos, puede usar algo como esto(trabajando con python >= 2.6, incluyendo 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}")

El(los) carácter (s) malo (s) en la cadena se convertirá (n) en una representación que se puede imprimir en la consola de Windows.

 14
Author: Giampaolo Rodolà,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-19 18:48:28

El siguiente código hará que Python salga a la consola como UTF-8 incluso en Windows.

La consola mostrará bien los caracteres en Windows 7, pero en Windows XP no los mostrará bien, pero al menos funcionará y lo más importante es que tendrá una salida consistente de su script en todas las plataformas. Podrás redirigir la salida a un archivo.

El siguiente código fue probado con Python 2.6 en 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"
 10
Author: sorin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-12 20:45:44

Como la respuesta de Giampaolo Rodolà, pero aún más sucia: Realmente, realmente tengo la intención de pasar mucho tiempo (pronto) entendiendo todo el tema de las codificaciones y cómo se aplican a las consolas Windoze,

Por el momento solo quería sthg, lo que significaría que mi programa NO se BLOQUEARÍA, y lo entendí ... y también que no implicó importar demasiados módulos exóticos (en particular, estoy usando Jython, por lo que la mitad del tiempo un módulo de Python resulta no ser disponible).

def pr(s):
    try:
        print(s)
    except UnicodeEncodeError:
        for c in s:
            try:
                print( c, end='')
            except UnicodeEncodeError:
                print( '?', end='')

NB "pr" es más corto para escribir que "print" (y bastante más corto para escribir que "safeprint")...!

 3
Author: mike rodent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-09 22:14:15

Para Python 2 intente:

print unicode(string, 'unicode-escape')

Para Python 3 intente:

import os
string = "002 Could've Would've Should've"
os.system('echo ' + string)

O prueba win-unicode-console:

pip install win-unicode-console
py -mrun your_script.py
 3
Author: shubaly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-17 05:07:50

La causa de su problema es NO la consola Win no está dispuesta a aceptar Unicode (ya que lo hace ya que supongo que Win2k por defecto). Es la codificación predeterminada del sistema. Pruebe este código y vea lo que le da:

import sys
sys.getdefaultencoding()

Si dice ascii, ahí está tu causa ;-) Tienes que crear un archivo llamado sitecustomize.py y lo puse bajo python path (lo puse bajo / usr / lib/python2. 5 / site-packages, pero eso es diferente en Win - es c:\python\lib\site-packages o algo así), con el siguiente contenido:

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

Y tal vez desee especificar la codificación en sus archivos también:

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

Editar: se puede encontrar más información en excellent the Dive into Python book

 2
Author: Bartosz Radaczyński,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-04 01:52:54

Algo relacionado con la respuesta de J. F. Sebastian, pero más directo.

Si tiene este problema al imprimir en la consola / terminal, haga lo siguiente:

>set PYTHONIOENCODING=UTF-8
 1
Author: Kinjal Dixit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-16 07:53:43

Python 3.6 windows7: Hay varias maneras de lanzar un python que podría utilizar la consola python (que tiene un logotipo de python en él) o la consola de Windows (está escrito cmd.exe en él).

No pude imprimir caracteres utf8 en la consola de Windows. Imprimir caracteres utf-8 me arroja este error:

OSError: [winError 87] The paraneter is incorrect 
Exception ignored in: (_io-TextIOwrapper name='(stdout)' mode='w' ' encoding='utf8') 
OSError: [WinError 87] The parameter is incorrect 

Después de intentar y no entender la respuesta anterior descubrí que era solo un problema de configuración. Haga clic derecho en la parte superior de las ventanas de la consola cmd, en la pestaña font chose consola lucida.

 1
Author: J. Does,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-11 20:08:34

TL; DR:

print(yourstring.encode('ascii','replace'));

Me encontré con esto yo mismo, trabajando en un bot de Twitch chat (IRC). (Python 2.7 latest)

Quería analizar los mensajes de chat para responder...

msg = s.recv(1024).decode("utf-8")

Pero también imprímalos de forma segura en la consola en un formato legible por humanos:

print(msg.encode('ascii','replace'));

Esto corrigió el problema de los errores de lanzamiento del bot UnicodeEncodeError: 'charmap' y reemplazó los caracteres unicode con ?.

 1
Author: Matthew Estock,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-01 15:52:05

James Sulak preguntó,

¿Hay alguna manera de hacer que Python imprima automáticamente a ? en lugar de fallar en esta situación?

Otras soluciones recomiendan que intentemos modificar el entorno Windows o reemplazar la función print() de Python. La respuesta a continuación se acerca más al cumplimiento de la solicitud de Sulak.

Bajo Windows 7, Python 3.5 se puede hacer para imprimir Unicode sin lanzar un UnicodeEncodeError de la siguiente manera:

En lugar de:    print(text)
    sustituir:     print(str(text).encode('utf-8'))

En lugar de lanzar una excepción, Python ahora muestra caracteres Unicode no imprimibles como \xNN códigos hexadecimales, por ejemplo:

Halmalo n \ xe2 \ x80\x99\xc3 \ xa9tait plus qu\xe2\x80 \ x99un point noir

En lugar de

Halmalo n'était plus qu'un point noir

Concedido, el último es preferible ceteris paribus, pero por lo demás el primero es completamente preciso para los mensajes de diagnóstico. Porque muestra Unicode como valores literales de bytes el primero también puede ayudar en el diagnóstico de problemas de codificación / decodificación.

Nota: La llamada str() anterior es necesaria porque de lo contrario encode() hace que Python rechace un carácter Unicode como una tupla de números.

 0
Author: CODE-REaD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-24 16:19:05

Simplemente ingrese este código en la línea de comandos antes de ejecutar el script python:

chcp 65001 & set PYTHONIOENCODING=utf-8
 0
Author: c97,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-10-02 22:11:03