【发布时间】:2012-11-19 11:33:49
【问题描述】:
我在 Windows 8 中使用 CMD,并将代码页设置为 65001 (chcp 65001)。我正在使用 Python 2.7.2 (ActivePython 2.7.2.5),并且已将 PYTHONSTARTUP 环境变量设置为“bootstrap.py”。
bootstrap.py:
import codecs
codecs.register(
lambda name: name == 'cp65001' and codecs.lookup('UTF-8') or None
)
这让我可以打印 ASCII:
>>> print 'hello'
hello
>>> print u'hello'
hello
但是当我尝试使用非 ASCII 字符打印 Unicode 字符串时遇到的错误对我来说毫无意义。这里我尝试打印一些包含北欧符号的字符串(为了便于阅读,我在打印之间添加了额外的换行符):
>>> print u'æøå'
��øåTraceback (most recent call last):
File "<stdin>", line 1, in <module>
IOError: [Errno 2] No such file or directory
>>> print u'åndalsnes'
��ndalsnes
>>> print u'åndalsnesæ'
��ndalsnesæTraceback (most recent call last):
File "<stdin>", line 1, in <module>
IOError: [Errno 22] Invalid argument
>>> print u'Øst'
��st
>>> print u'uØst'
uØstTraceback (most recent call last):
File "<stdin>", line 1, in <module>
IOError: [Errno 22] Invalid argument
>>> print u'ØstÆØÅæøå'
��stÆØÅæøåTraceback (most recent call last):
File "<stdin>", line 1, in <module>
IOError: [Errno 22] Invalid argument
>>> print u'_ØstÆØÅæøå'
_ØstÆØÅæøåTraceback (most recent call last):
File "<stdin>", line 1, in <module>
IOError: [Errno 22] Invalid argument
正如您所见,它并不总是引发错误(甚至不会每次都引发相同的错误),而且北欧符号只是偶尔正确显示。
谁能解释一下这种行为,或者至少帮我弄清楚如何正确地将 Unicode 打印到 CMD?
【问题讨论】:
-
这是一场噩梦。在 SO 和其他地方已经讨论了无数次。例如:google.com/search?q=print+unicode+windows+console+python
-
@DavidHeffernan:我查看了搜索结果,我能找到的最接近规范答案的是 OP 已经在做的事情。在我看来,要么这是一个新变体,要么这个问题从未真正得到正确回答?
-
至少在 3.3 中改进了对 Windows 代码页的支持:PyUnicode_EncodeCodePage。后者由
codecs.code_page_encode使用,新的 cp65001 编解码器使用它来定义encode = functools.partial(codecs.code_page_encode, 65001),解码类似。 -
目前
PRINT_ITEM操作调用PyFile_WriteObject,后者调用PyObject_Print,最终调用PyString_Type.tp_print,后者使用libcfwrite写入标准输出。有问题的是一个错误导致 stdoutFILE流设置其错误标志,即使没有发生错误(因此报告了随机“错误”),因为write返回写入的字符数而不是字符数字节。您可以使用os.write(sys.stdout.fileno(), s)来验证这一点,其中s是一个非ASCII UTF-8 字符串。 -
这在 Python 3 中不是问题,因为它实现了自己的缓冲 (
_io.BufferedWriter),并且底层_io.FileIO对目标文件描述符执行低级write。