Python, Unicode e o console do Windows
Pergunta
Quando tento imprimir uma string Unicode em um console do Windows, recebo uma mensagem UnicodeEncodeError: 'charmap' codec can't encode character ....
erro.Presumo que isso ocorra porque o console do Windows não aceita caracteres somente Unicode.Qual é a melhor maneira de contornar isso?Existe alguma maneira de fazer o Python imprimir automaticamente um ?
em vez de falhar nesta situação?
Editar: Estou usando Python 2.5.
Observação: A resposta do @LasseV.Karlsen com a marca de seleção está meio desatualizada (de 2008).Por favor, use as soluções/respostas/sugestões abaixo com cuidado!!
Resposta @JFSebastian é mais relevante a partir de hoje (6 de janeiro de 2016).
Solução
Observação: Esta resposta está meio desatualizada (de 2008).Por favor, use a solução abaixo com cuidado!!
Aqui está uma página que detalha o problema e uma solução (procure na página o texto Envolvendo sys.stdout em uma instância):
Aqui está um trecho de código dessa 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
Б
Б
Há mais algumas informações nessa página, vale a pena ler.
Outras dicas
Atualizar: Pitão 3.6 implementos PEP 528:Altere a codificação do console do Windows para UTF-8: o console padrão do Windows agora aceitará todos os caracteres Unicode. Internamente, ele usa a mesma API Unicode que o win-unicode-console
pacote mencionado abaixo. print(unicode_string)
deve funcionar agora.
Eu recebo um
UnicodeEncodeError: 'charmap' codec can't encode character...
erro.
O erro significa que os caracteres Unicode que você está tentando imprimir não podem ser representados usando o atual (chcp
) codificação de caracteres do console.A página de código geralmente é uma codificação de 8 bits, como cp437
que pode representar apenas aproximadamente 0x100 caracteres de aproximadamente 1 milhão de 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
Presumo que isso ocorra porque o console do Windows não aceita caracteres somente Unicode.Qual é a melhor maneira de contornar isso?
O console do Windows aceita caracteres Unicode e pode até exibi-los (somente BMP) se a fonte correspondente estiver configurada. WriteConsoleW()
A API deve ser usada conforme sugerido em Resposta de @Daira Hopwood.Ele pode ser chamado de forma transparente, ou seja, você não precisa e não deve modificar seus scripts se usar win-unicode-console
pacote:
T:\> py -mpip install win-unicode-console
T:\> py -mrun your_script.py
Ver Qual é o problema com Python 3.4, Unicode, diferentes linguagens e Windows?
Existe alguma maneira de fazer Python imprimir automaticamente um
?
em vez de falhar nesta situação?
Se for suficiente substituir todos os caracteres não codificáveis por ?
no seu caso, então você pode definir PYTHONIOENCODING
envvar:
T:\> set PYTHONIOENCODING=:replace
T:\> python3 -c "print(u'[\N{EURO SIGN}]')"
[?]
No Python 3.6+, a codificação especificada por PYTHONIOENCODING
envvar é ignorado para buffers de console interativos, a menos que PYTHONLEGACYWINDOWSIOENCODING
envvar é definido como uma string não vazia.
Apesar das outras respostas aparentemente plausíveis que sugerem alterar a página de código para 65001, isso não funciona.(Além disso, alterar a codificação padrão usando sys.setdefaultencoding
é não é uma boa ideia.)
Ver essa questão para obter detalhes e código que funciona.
Se você não estiver interessado em obter uma representação confiável dos caracteres ruins, você pode usar algo assim (trabalhando com python >= 2.6, incluindo 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}")
Os caracteres inválidos na string serão convertidos em uma representação que pode ser impressa pelo console do Windows.
O código abaixo fará com que a saída do Python seja console como UTF-8, mesmo no Windows.
O console exibirá bem os caracteres no Windows 7, mas no Windows XP não os exibirá bem, mas pelo menos funcionará e o mais importante, você terá uma saída consistente do seu script em todas as plataformas.Você poderá redirecionar a saída para um arquivo.
O código abaixo foi testado com Python 2.6 no 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"
Como a resposta de Giampaolo Rodolà, mas ainda mais suja:Eu realmente pretendo passar muito tempo (em breve) entendendo todo o assunto das codificações e como elas se aplicam aos consoles Windoze,
No momento eu só queria algo que significasse que meu programa NÃO iria travar, e que eu entendi ...e também que não envolveu a importação de muitos módulos exóticos (em particular, estou usando Jython, então na metade das vezes um módulo Python não está disponível).
def pr(s):
try:
print(s)
except UnicodeEncodeError:
for c in s:
try:
print( c, end='')
except UnicodeEncodeError:
print( '?', end='')
NB "pr" é mais curto para digitar do que "print" (e um pouco mais curto para digitar do que "safeprint")...!
Basta inserir este código na linha de comando antes de executar o script python:
chcp 65001 & set PYTHONIOENCODING=utf-8
Para Python 2, tente:
print unicode(string, 'unicode-escape')
Para Python 3, tente:
import os
string = "002 Could've Would've Should've"
os.system('echo ' + string)
Ou tente win-unicode-console:
pip install win-unicode-console
py -mrun your_script.py
A causa do seu problema é NÃO o console do Win não está disposto a aceitar Unicode (pois faz isso, pois acho que o Win2k é o padrão).É a codificação padrão do sistema.Experimente este código e veja o que ele oferece:
import sys
sys.getdefaultencoding()
Se diz ASCII, há sua causa ;-) Você precisa criar um arquivo chamado sitecustomize.py e colocá-lo no caminho do Python (eu o coloquei em /usr/lib/python2.5/site-packages, mas isso é diferente em Win - é c: python lib sites packages ou algo assim), com o seguinte conteúdo:
import sys
sys.setdefaultencoding('utf-8')
e talvez você também queira especificar a codificação em seus arquivos:
# -*- coding: UTF-8 -*-
import sys,time
Editar:mais informações podem ser encontradas em excelente o livro Dive into Python
DR:
print(yourstring.encode('ascii','replace'));
Eu mesmo me deparei com isso, trabalhando em um bot de chat do Twitch (IRC).(Python 2.7 mais recente)
Eu queria analisar mensagens de bate-papo para responder...
msg = s.recv(1024).decode("utf-8")
mas também imprima-os com segurança no console em um formato legível:
print(msg.encode('ascii','replace'));
Isso corrigiu o problema do lançamento do bot UnicodeEncodeError: 'charmap'
erros e substituiu os caracteres Unicode por ?
.
Meio relacionado na resposta de J.F.Sebastian, mas mais direto.
Se você estiver tendo esse problema ao imprimir no console/terminal, faça o seguinte:
>set PYTHONIOENCODING=UTF-8
Python 3.6 windows7:Existem várias maneiras de iniciar um python: você pode usar o console python (que tem um logotipo python) ou o console do Windows (está escrito cmd.exe nele).
Não consegui imprimir caracteres utf8 no console do Windows.Imprimir caracteres utf-8 gera este erro:
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
Depois de tentar e não entender a resposta acima, descobri que era apenas um problema de configuração.Clique com o botão direito na parte superior das janelas do console cmd, na guia font
escolheu console lúcida.
James Sulak perguntou:
Existe alguma maneira de fazer o Python imprimir automaticamente um arquivo ?em vez de falhar nesta situação?
Outras soluções recomendam que tentemos modificar o ambiente Windows ou substituir o ambiente do Python print()
função.A resposta abaixo chega mais perto de atender ao pedido de Sulak.
No Windows 7, o Python 3.5 pode ser feito para imprimir Unicode sem lançar um UnicodeEncodeError
do seguinte modo:
No lugar de:print(text)
substituto: print(str(text).encode('utf-8'))
Em vez de lançar uma exceção, o Python agora exibe caracteres Unicode não imprimíveis como \xNN códigos hexadecimais, por exemplo:
Halmalo n\xe2\x80\x99\xc3\xa9tait mais qu\xe2\x80\x99un ponto preto
Em vez de
Halmalo n'était plus qu'un point noir
É verdade que o último é preferível ceteris paribus, mas por outro lado o primeiro é completamente preciso para mensagens de diagnóstico.Como exibe Unicode como valores de bytes literais, o primeiro também pode ajudar no diagnóstico de problemas de codificação/decodificação.
Observação: O str()
a chamada acima é necessária porque caso contrário encode()
faz com que o Python rejeite um caractere Unicode como uma tupla de números.