Python, Unicode и консоль Windows

Когда я пытаюсь напечатать строку Unicode в консоли Windows, я получаю сообщение об ошибке.

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

Я предполагаю, что это связано с тем, что консоль Windows не принимает символы только Unicode. Как лучше всего обойти это? Есть ли способ заставить Python автоматически печатать a ? вместо сбоя в этой ситуации?

Изменить: я использую Python 2.5.


Примечание: ответ @ LasseV.Karlsen с галочкой вроде как устарел (с 2008 года). Пожалуйста, используйте приведенные ниже решения / ответы / предложения с осторожностью!

Ответ @JFSebastian более актуален на сегодняшний день (6 января 2016 г.).

Ответов (13)

Решение

Примечание: этот ответ вроде как устарел (с 2008 года). Пожалуйста, используйте приведенное ниже решение с осторожностью!


Вот страница с подробным описанием проблемы и решения (найдите на странице текст Перенос sys.stdout в экземпляр ):

PrintFails - Python Wiki

Вот отрывок кода с этой страницы:

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

На этой странице есть дополнительная информация, которую стоит прочитать.

Если вас не интересует надежное представление плохого символа (ов), вы можете использовать что-то вроде этого (работая с python> = 2.6, включая 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}")

Неправильный символ (символы) в строке будет преобразован в представление, которое можно распечатать с помощью консоли Windows.

Отчасти связано с ответом Дж. Ф. Себастьяна, но более прямым.

Если у вас возникла эта проблема при печати на консоль / терминал, сделайте следующее:

>set PYTHONIOENCODING=UTF-8

Как и ответ Джампаоло Родола, но еще более грязный: я действительно, действительно намерен потратить много времени (скоро) на понимание всего предмета кодирования и того, как они применяются к консолям Windoze,

На данный момент я просто хотел sthg, что означало бы, что моя программа НЕ БУДЕТ СБОЙ, и что я понял ... а также который не включал импорт слишком большого количества экзотических модулей (в частности, я использую Jython, поэтому в половине случаев Python модуль фактически недоступен).

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

NB «pr» короче для ввода, чем «print» (и немного короче для набора, чем «safeprint») ...!

Джеймс Сулак спросил:

Есть ли способ заставить Python автоматически печатать? вместо того, чтобы потерпеть неудачу в этой ситуации?

Другие решения рекомендуют попытаться изменить среду Windows или заменить print() функцию Python . Ответ ниже приближается к выполнению запроса Сулака.

В Windows 7 можно заставить Python 3.5 печатать Unicode без использования UnicodeEncodeError следующего символа :

    Вместо:     print(text)
    замените:     print(str(text).encode('utf-8'))

Вместо того, чтобы генерировать исключение, Python теперь отображает непечатаемые символы Unicode в виде шестнадцатеричных кодов \ xNN , например:

  Халмало n \ xe2 \ x80 \ x99 \ xc3 \ xa9tait plus qu \ xe2 \ x80 \ x99un поинт нуар

Вместо того

  Halmalo n'était plus qu'un point noir

Конечно, последнее предпочтительнее при прочих равных условиях , но в остальном первое является полностью точным для диагностических сообщений. Поскольку он отображает Unicode как буквальные байтовые значения, первый также может помочь в диагностике проблем кодирования / декодирования.

Примечание: str() вызов выше необходимо , потому что в противном случае encode() приводит к Python , чтобы отклонить символ Unicode как кортеж чисел.

Python 3.6 windows7: есть несколько способов запустить python, вы можете использовать консоль python (на которой есть логотип python) или консоль Windows (на ней написано cmd.exe).

Я не мог печатать символы utf8 в консоли Windows. Печать символов utf-8 вызывает у меня эту ошибку:

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 

Попробовав и не сумев понять приведенный выше ответ, я обнаружил, что это всего лишь проблема с настройками. Щелкните правой кнопкой мыши в верхней части окна консоли cmd, на вкладке выберите font консоль lucida.

TL; DR:

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

Я сам столкнулся с этим, работая над ботом чата Twitch (IRC). (Последняя версия Python 2.7)

Я хотел разобрать сообщения чата, чтобы ответить ...

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

но также безопасно распечатать их на консоли в удобочитаемом формате:

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

Это устранило проблему с UnicodeEncodeError: 'charmap' ошибками броска ботом и заменило символы юникода на ? .

Для Python 2 попробуйте:

print unicode(string, 'unicode-escape')

Для Python 3 попробуйте:

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

Или попробуйте win-unicode-console:

pip install win-unicode-console
py -mrun your_script.py

Несмотря на другие правдоподобно звучащие ответы, предлагающие изменить кодовую страницу на 65001, это не работает . (Кроме того , изменение кодировки по умолчанию , используя sys.setdefaultencoding это не очень хорошая идея .)

См. Этот вопрос для получения подробной информации и кода, который действительно работает.

Просто введите этот код в командную строку перед выполнением скрипта python:

chcp 65001 & set PYTHONIOENCODING=utf-8

Причина вашей проблемы НЕ в том, что консоль Win не желает принимать Unicode (поскольку она делает это, поскольку я предполагаю, что Win2k по умолчанию). Это системная кодировка по умолчанию. Попробуйте этот код и посмотрите, что он вам дает:

import sys
sys.getdefaultencoding()

если он говорит ascii, это ваша причина ;-) Вы должны создать файл с именем sitecustomize.py и поместить его по пути python (я поместил его в /usr/lib/python2.5/site-packages, но он отличается от Win - это c: \ python \ lib \ site-packages или что-то в этом роде) со следующим содержимым:

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

и, возможно, вы также можете указать кодировку в своих файлах:

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

Изменить: дополнительную информацию можно найти в отличной книге Dive into Python

Приведенный ниже код будет выводить Python на консоль как UTF-8 даже в Windows.

Консоль будет хорошо отображать символы в Windows 7, но в Windows XP она не будет хорошо их отображать, но, по крайней мере, она будет работать, и, что наиболее важно, у вас будет согласованный вывод вашего сценария на всех платформах. Вы сможете перенаправить вывод в файл.

Код ниже был протестирован с Python 2.6 в 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"

Обновление: Python 3.6 реализует PEP 528: измените кодировку консоли Windows на UTF-8 : консоль по умолчанию в Windows теперь будет принимать все символы Unicode. Внутри он использует тот же Unicode API, что и win-unicode-consoleупомянутый ниже пакет . print(unicode_string) должен просто работать сейчас.


Я получаю UnicodeEncodeError: 'charmap' codec can't encode character... ошибку

Ошибка означает, что символы Unicode, которые вы пытаетесь распечатать, не могут быть представлены с использованием chcp кодировки символов консоли current ( ). Кодовая страница часто представляет собой 8-битную кодировку, например, cp437 которая может представлять только ~ 0x100 символов из ~ 1M символов Unicode:

>>> u "\ N {ЗНАК ЕВРО}". encode ('cp437')
Отслеживание (последний вызов последний):
...
UnicodeEncodeError: кодек 'charmap' не может кодировать символ '\ u20ac' в позиции 0:
символы сопоставляются с 

Я предполагаю, что это связано с тем, что консоль Windows не принимает символы только Unicode. Как лучше всего обойти это?

Консоль Windows принимает символы Unicode и даже может отображать их (только BMP), если настроен соответствующий шрифт . WriteConsoleW() API следует использовать, как это предлагается в ответе @Daira Hopwood . Его можно вызывать прозрачно, то есть вам не нужно и не следует изменять свои скрипты, если вы используете win-unicode-consolepackage :

T:\> py -m pip install win-unicode-console
T:\> py -m run your_script.py

Посмотрите, что такое Python 3.4, Unicode, разные языки и Windows?

Есть ли способ заставить Python автоматически печатать a ?вместо сбоя в этой ситуации?

Если ? в вашем случае достаточно заменить все некодируемые символы на, вы можете установить PYTHONIOENCODINGenvvar :

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

В Python 3.6+ кодировка, указанная PYTHONIOENCODING envvar, игнорируется для буферов интерактивной консоли, если PYTHONLEGACYWINDOWSIOENCODING envvar не установлена ​​на непустую строку.