Какая сделка с Python 3.4, Unicode, разными языками и Windows?

Счастливые примеры:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

czech = u'Leoš Janáček'.encode("utf-8")
print(czech)

pl = u'Zdzisław Beksiński'.encode("utf-8")
print(pl)

jp = u'リング 山村 貞子'.encode("utf-8")
print(jp)

chinese = u'五行'.encode("utf-8")
print(chinese)

MIR = u'Машина для Инженерных Расчётов'.encode("utf-8")
print(MIR)

pt = u'Minha Língua Portuguesa: çáà'.encode("utf-8")
print(pt)

Несчастливый выход:

b'Leo\xc5\xa1 Jan\xc3\xa1\xc4\x8dek'
b'Zdzis\xc5\x82aw Beksi\xc5\x84ski'
b'\xe3\x83\xaa\xe3\x83\xb3\xe3\x82\xb0 \xe5\xb1\xb1\xe6\x9d\x91 \xe8\xb2\x9e\xe5\xad\x90'
b'\xe4\xba\x94\xe8\xa1\x8c'
b'\xd0\x9c\xd0\xb0\xd1\x88\xd0\xb8\xd0\xbd\xd0\xb0 \xd0\xb4\xd0\xbb\xd1\x8f \xd0\x98\xd0\xbd\xd0\xb6\xd0\xb5\xd0\xbd\xd0\xb5\xd1\x80\xd0\xbd\xd1\x8b\xd1\x85 \xd0\xa0\xd0\xb0\xd1\x81\xd1\x87\xd1\x91\xd1\x82\xd0\xbe\xd0\xb2'
b'Minha L\xc3\xadngua Portuguesa: \xc3\xa7\xc3\xa1\xc3\xa0'

И если я напечатаю их следующим образом:

jp = u'リング 山村 貞子'
print(jp)

Я получаю:

Traceback (most recent call last):
  File "x.py", line 5, in <module>
    print(jp)
  File "C:\Python34\lib\encodings\cp850.py", line 19, in encode
    return codecs.charmap_encode(input,self.errors,encoding_map)[0]
UnicodeEncodeError: 'charmap' codec can't encode characters in position
0-2: character maps to <undefined>

Я также пробовал следующее из этого вопроса (и другие варианты, которые включают sys.stdout.encoding):

#!/usr/bin/env python
# -*- coding: utf-8 -*-

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'))

jp = u'リング 山村 貞子'
safeprint(jp)

И все становится еще более загадочным:

リング 山村 貞子

И документы не были очень полезными.

Итак, что такое сделка с Python 3.4, Unicode, разными языками и Windows? Почти все возможные примеры, которые я мог найти, касаются Python 2.x.

Существует ли общий и кросс-платформенный способ печати любого символа Unicode с любого языка в достойном и неприглядном виде в Python 3.4?

EDIT:

Я пробовал печатать на терминале:

chcp 65001

Чтобы изменить кодовую страницу как предлагается здесь, и в комментариях, и это не сработало (включая попытку с sys.stdout.encoding)

Ответы

Ответ 1

Задача была (см. ниже Python 3.6) с консолью Windows, которая поддерживает набор символов ANSI, подходящий для региона, ориентированного на вашу версию Windows. Python генерирует исключение по умолчанию при выводе неподдерживаемых символов.

Python может читать переменную окружения для вывода в других кодировках или для изменения обработки ошибок по умолчанию. Ниже я прочитал консоль по умолчанию и изменил обработку ошибок по умолчанию, чтобы напечатать ? вместо того, чтобы бросать ошибку для символов, которые не поддерживаются на текущей кодовой странице консоли.

C:\>chcp
Active code page: 437   # Note, US Windows OEM code page.

C:\>set PYTHONIOENCODING=437:replace

C:\>example.py
Leo? Janá?ek
Zdzis?aw Beksi?ski
??? ?? ??
??
?????? ??? ?????????? ????????
Minha Língua Portuguesa: çáà

Обратите внимание, что кодовая страница OEM-производителя США ограничена ASCII и некоторыми западноевропейскими символами.

Ниже я поручил Python использовать UTF8, но поскольку консоль Windows не поддерживает его, я перенаправляю вывод в файл и выводит его в Блокнот:

C:\>set PYTHONIOENCODING=utf8
C:\>example >out.txt
C:\>notepad out.txt

enter image description here

В Windows лучше использовать среду разработки Python, которая поддерживает UTF-8 вместо консоли при работе с несколькими языками. Если используется только один язык, выберите его в качестве языкового стандарта системы на панели управления Region and Language, а консоль будет поддерживать символы этого языка.

Обновление для Python 3.6

Теперь Python 3.6 использует API-интерфейсы Windows Unicode для прямой записи на консоль, поэтому единственным ограничением является поддержка шрифтов в консоли для символов. Следующий код работает на консоли Windows Windows. У меня установлен пакет на китайском языке, он даже отображает китайский и японский языки, если шрифт консоли изменен. Даже без правильного шрифта заменяющие символы отображаются на консоли. Cut-n-paste для среды, такой как эта веб-страница, отобразит символы правильно.

#!python3.6
#coding: utf8
czech = 'Leoš Janáček'
print(czech)

pl = 'Zdzisław Beksiński'
print(pl)

jp = 'リング 山村 貞子'
print(jp)

chinese = '五行'
print(chinese)

MIR = 'Машина для Инженерных Расчётов'
print(MIR)

pt = 'Minha Língua Portuguesa: çáà'
print(pt)

Вывод:

Leoš Janáček
Zdzisław Beksiński
リング 山村 貞子
五行
Машина для Инженерных Расчётов
Minha Língua Portuguesa: çáà

Ответ 2

Обновление: Начиная с Python 3.6, пример кода, который печатает строки Unicode напрямую, должен работать только сейчас (даже без py -mrun).


Python может печатать текст на нескольких языках в консоли Windows, независимо от того, что chcp говорит:

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

где your_script.py печатает Unicode напрямую, например:

#!/usr/bin/env python3
print('š áč')      # cz
print('ł ń')       # pl
print('リング')     # jp
print('五行')      # cn
print('ш я жх ё') # ru
print('í çáà')    # pt

Все, что вам нужно - это настроить шрифт в консоли Windows, который может отображать нужные символы.

Вы также можете запустить свой Python script через IDLE без установки модулей non-stdlib:

T:\> py -midlelib -r your_script.py

Чтобы записать файл/трубу, используйте PYTHONIOENCODING=utf-8 в качестве @Mark Tolonen:

T:\> set PYTHONIOENCODING=utf-8
T:\> py your_script.py >output-utf8.txt 

Только последнее решение поддерживает символы без BMP, такие как 😒 (U + 1F612 UNAMUSED FACE) - py -mrun может писать их но консоль Windows отображает их в виде блоков, даже если шрифт поддерживает соответствующие символы Юникода (хотя вы можете скопировать вставки в другую программу, чтобы получить символы).