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

Когда я пытаюсь напечатать строку Unicode в консоли Windows, я получаю ошибку UnicodeEncodeError: 'charmap' codec can't encode character ..... Я предполагаю, что это связано с тем, что консоль Windows не принимает символы только для Юникода. Какой лучший способ? Есть ли способ заставить Python автоматически печатать ? вместо отказа в этой ситуации?

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


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

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

Ответы

Ответ 1

Примечание: Этот ответ несколько устарел (с 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
  Б
  Б

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

Ответ 2

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


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

Ошибка означает, что символы Unicode, которые вы пытаетесь распечатать, не могут быть представлены с использованием текущей (chcp) кодировки символов консоли. Кодовая страница часто представляет собой 8-битное кодирование, такое как cp437, которое может представлять только ~ 0x100 символов из символов 1M 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 

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

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

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

Смотрите Что такое сделка с Python 3.4, Unicode, разными языками и Windows?

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

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

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

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

Ответ 3

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

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

Ответ 4

Если вам не интересно получать достоверное представление о плохом персонаже, вы можете использовать что-то вроде этого (работая с 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.

Ответ 5

Следующий код сделает вывод Python на консоль как UTF-8 даже в Windows.

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

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

Ответ 6

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

На данный момент я просто хотел sthg, что означало бы, что моя программа не будет CRASH, и которая я понял... а также которая не включала в себя импорт слишком большого количества экзотических модулей (в частности, я использую 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" (и немного короче, чем "безопасный" )...!

Ответ 7

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.

Ответ 8

Для Python 2 попробуйте:
print unicode (строка, 'unicode-escape')

Для Python 3 попробуйте:
import os
string = '002 Couldve Wasve Shouldve'
os.system('echo' + string)

Или попробуйте win-unicode-console:
pip install win-unicode-console
py -mrun your_script.py

Ответ 9

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

import sys
sys.getdefaultencoding()

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

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

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

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

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

Ответ 10

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

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

>set PYTHONIOENCODING=UTF-8

Ответ 11

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

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

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

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

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

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

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

Вместо

  Halmalo nétait plus quun point noir

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

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