Python 3.4、Unicode、不同语言和Windows有什么关系?

27

愉快的例子:

#!/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有关。

是否存在一种通用和跨平台的方法,在Python 3.4中以良好且非恶心的方式打印任何语言的任何Unicode字符?

编辑:

我尝试在终端输入:

chcp 65001

要更改代码页,可以像这里和评论中提出的那样尝试,但是并没有成功(包括使用sys.stdout.encoding的尝试)。

1
您的控制台未配置为Unicode输出;CP850无法处理那么多内容。 - Martijn Pieters
我期望得到与我放入字符串中的相同的东西。 - Ericson Willians
@Padraic,问题出在Windows上,但责任在于兼容性要求,即所谓的“历史原因”。(http://blogs.msdn.com/b/oldnewthing/archive/2005/03/08/389527.aspx) - TigerhawkT3
4
Windows控制台可以正常打印Unicode字符串(假设字体支持Unicode),使用WriteConsoleW,但Python没有使用它,详见https://bugs.python.org/issue1602。 - Philipp
显示剩余2条评论
2个回答

21

更新:自Python 3.6以来,直接打印Unicode字符串的代码示例现在应该可以正常工作(即使没有py -mrun)。


在Windows控制台中,Python可以打印多种语言的文本,无论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控制台中配置字体,以显示所需的字符。

您也可以通过IDLE运行Python脚本,而无需安装非标准库模块:

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不高兴的脸) - py -mrun可以写入它们,但是Windows控制台会将它们显示为方框,即使字体支持相应的Unicode字符(但您可以将这些方框复制粘贴到另一个程序中以获取字符)。

你会如何进行交互式版本?我猜Python是python -i -m run,但是我无法弄清楚ipython,尽管win-unicode-console的页面上指出它已经集成了。 - hyperknot
@zsero:文档展示了几种方法,例如,py -i -m run c:\path\to\ipython。您还可以使用qtconsole界面或基于Web浏览器的笔记本。如果无法正常工作,请提出一个单独的问题,说明您想要使用ipython做什么以及具体失败的原因。 - jfs
@eryksun:不是。请注意使用了 py -m run 命令。 - jfs
@sebastian,我想我在你的帮助下解决了我的问题。你的回答有点令人困惑:作为一个Python 3.6用户,我不知道是否应该忽略或考虑你在下面写的内容。如果是这样的话,“对于以前的版本:”这样的说明会更清晰明了。感谢你的耐心! - JinSnow
1
Lucida console 不支持中文或日文。 - Mark Tolonen
显示剩余3条评论

13

问题曾经存在于Windows控制台,它支持与您的Windows版本所针对的区域相适应的ANSI字符集。当输出不受支持的字符时,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上,当涉及到多种语言时最好使用支持UTF-8的Python IDE而不是控制台。如果只使用一种语言,请将其选择为系统区域设置中的语言,这样控制台就能支持该语言的字符。
Python 3.6现在使用Windows Unicode API直接写入控制台,所以唯一的限制是控制台字体对字符的支持。以下代码在美国Windows控制台中有效。我安装了中文语言包,它甚至可以显示中文和日文(如果更改控制台字体)。即使没有正确的字体,替换字符也会在控制台中显示。将其复制粘贴到像这个网页这样的环境中,字符将被正确地显示。
#!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: çáà

3
Windows控制台可以使用WriteConsoleW打印任意Unicode字符串(受字体支持限制,且无法正确处理非BMP字符)。Python没有使用该函数,请参阅https://bugs.python.org/issue1602进行一些讨论。 - Philipp
Python 3.6:您需要配置控制台:右键单击窗口顶部(cmd或Python IDLE),在默认/字体中选择“Lucida控制台”。 - JinSnow
1
@Guillaume 对于中文/日文无济于事。我在Windows 10中安装了中文语言包,然后就有了新的控制台字体。SimSun字体看起来很好,并支持以上六种语言。 - Mark Tolonen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接