Как печатать utf-8 для консоли с Python 3.4 (Windows 8)?

Я никогда полностью не обволакивал кодировку и декодирование unicode в другие форматы (utf-8, utf-16, ascii и т.д.), но я дошел до стены, что и запутывает, и расстраивает. То, что я пытаюсь сделать, это напечатать символы карты utf-8 (♠, ♥, ♦, ♣) из модуля python в консоль Windows. Консоль, которую я использую, - git bash, и я использую console2 в качестве интерфейсного. Я пробовал/читал несколько подходов ниже, и до сих пор ничего не работало. Дайте мне знать, возможно ли, что я делаю, и правильный способ сделать это.

  • Убедитесь, что консоль может обрабатывать символы utf-8. Эти два теста заставляют меня поверить, что консоль не проблема.

enter image description here

  • Попытайтесь сделать то же самое из модуля python.
    Когда я выполняю .py, это результат.

    print(u'♠')
    UnicodeEncodeError: 'charmap' codec can't encode character '\u2660' in position 0: character maps to <undefined>
    
  • Попытка кодирования ♠. Это дает мне обратно набор юникодов, закодированный в utf-8, но все равно не символ лопаты.

    text = '♠'
    print(text.encode('utf-8'))
    b'\xe2\x99\xa0'
    

Мне кажется, что я пропускаю шаг или не понимаю весь процесс кодирования/декодирования. Я прочитал этот, этот и this. В последней из страниц предлагается обернуть sys.stdout в код, но эта статья говорит, что использование stdout не является необходимым и указывает на другую страницу с использованием модуля кодеков.

Я так смущен! Я чувствую, что документация по качеству мышления на эту тему трудно найти, и, надеюсь, кто-то может это прояснить. Любая помощь всегда приветствуется!

Остин

Ответы

Ответ 1

То, что я пытаюсь сделать, это напечатать символы карты utf-8 (♠, ♥, ♦, ♣) из модуля python в консоль Windows

UTF-8 является байтовым кодированием символов Unicode. ♠ ♥ ♦ ♣ являются символами Юникода, которые могут быть воспроизведены в различных кодировках, а UTF-8 является одним из этих кодировок - в качестве UTF, UTF-8 может воспроизводить любой символ Юникода. Но об этих персонажах нет ничего конкретно "UTF-8".

Другие кодировки, которые могут воспроизводить символы ♠ ♥ ♦ ♣, - это Windows кодовая страница 850 и 437, который, вероятно, будет использоваться вашей консолью под западноевропейской установкой Windows. Вы можете распечатать ♠ в этих кодировках, но вы не используете UTF-8, чтобы сделать это, и вы не сможете использовать другие символы Юникода, доступные в UTF-8, но выходящие за рамки этих кодовых страниц.

print(u'♠')
UnicodeEncodeError: 'charmap' codec can't encode character '\u2660'

В Python 3 это то же самое, что и тег print('♠'), который вы сделали выше, поэтому есть что-то другое в том, как вы вызываете script, содержащий этот print, по сравнению с вашим py -3.4. Что sys.stdout.encoding дает вам script?

Чтобы корректно работать с print, вы должны убедиться, что Python берет правильную кодировку. Если он не делает это должным образом из настроек терминала, вам действительно нужно установить PYTHONIOENCODING в cp437.

>>> text = '♠'
>>> print(text.encode('utf-8'))
b'\xe2\x99\xa0'

print может печатать только строки Unicode. Для других типов, включая строку bytes, которая получается из метода encode(), она получает буквальное представление (repr) объекта. b'\xe2\x99\xa0' заключается в том, как вы пишете литерал Python 3 байта, содержащий кодировку UTF-8 ♠.

Если вы хотите сделать обход print неявной кодировки PYTHONIOENCODING и заменить ее самостоятельно, вы можете сделать это явно:

>>> import sys
>>> sys.stdout.buffer.write('♠'.encode('cp437'))

Это, конечно, будет генерировать неверный вывод для любых консолей, не выполняющих кодовую страницу 437 (например, незападно-европейские установки). Как правило, для приложений, использующих C stdio, как это делает Python, получение символов, отличных от ASCII, на консоли Windows является слишком ненадежным, чтобы беспокоиться.

Ответ 3

По умолчанию консоль в Microsoft Windows отображает только 256 символов (cp437, "" Кодовая страница 437", оригинальный IBM-PC 1981 расширенный набор символов ASCII), как вы говорите в комментариях.

а с другой стороны PYTHONIOENCODING установлен по умолчанию UTF-8. поэтому я думаю, что когда вы хотите печатать юникод в окнах, вы должны выровнять sys.stdout.encoding и PYTHONIOENCODING вместе!

также обратите внимание, что при указании кодировки для вашего .py файла он просто использует его для этого кода и не меняет систему по умолчанию encoding.

сделайте что-то вроде этого:

import codecs
my_str='♠' # or something like my_str='\u05dd' 
my_str.encode().decode('cp437')

Ответ 4

Вы можете посмотреть на это таким образом. Строка представляет собой последовательность символов, а не последовательность байтов. Символы - это коды Unicode. Байты - это всего лишь цифры в диапазоне 0-255. На низком уровне компьютеры работают только с последовательностями байтов. Если вы хотите напечатать строку, вы просто вызываете print(a_string) в Python. Но для связи с средой ОС строка должна быть закодирована в последовательность байтов. Это делается автоматически под капотами функции print. Используемая кодировка sys.stdout.encoding. Если вы получаете UnicodeEncodeError, это означает, что ваши символы не могут быть закодированы с использованием текущей кодировки.

Насколько я знаю, в настоящее время невозможно запустить Python на Windows таким образом, что используемая кодировка способна кодировать каждый символ (как UTF-8 или UTF-16) и оба предполагаемые Python и действительно используемый средой ОС для ввода и вывода. Существует обходное решение - вы можете использовать пакет win_unicode_console, целью которого является решение этой проблемы. Просто установите его на pip install win_unicode_console, а в sitecustomize импортируйте его и вызовите win_unicode_console.enable(). Это будет являться внешним патчем для вашей установки Python, ставящей под угрозу эту проблему. Дополнительную информацию см. В документации: https://github.com/Drekin/win-unicode-console.