【问题标题】:Why do I get IOErrors when writing Unicode to the CMD? (With codepage 65001)为什么将 Unicode 写入 CMD 时会出现 IOErrors? (使用代码页 65001)
【发布时间】: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,后者使用libc fwrite 写入标准输出。有问题的是一个错误导致 stdout FILE 流设置其错误标志,即使没有发生错误(因此报告了随机“错误”),因为 write 返回写入的字符数而不是字符数字节。您可以使用os.write(sys.stdout.fileno(), s) 来验证这一点,其中s 是一个非ASCII UTF-8 字符串。
  • 这在 Python 3 中不是问题,因为它实现了自己的缓冲 (_io.BufferedWriter),并且底层 _io.FileIO 对目标文件描述符执行低级 write

标签: python windows windows-8


【解决方案1】:

试试这个:

# -*- coding: utf-8 -*-
    from __future__ import unicode_literals
    print u'æøå'

利用 from __future__ import unicode_literals交互式 python 会话中会很有用。

当然可以使用 WriteConsoleW 成功地将 Unicode 写入 console。无论控制台代码页如何,包括 65001,这都有效。代码 here 这样做(它适用于 Python 2.x,但无论如何您都会从 C 调用 WriteConsoleW)。

WriteConsoleW 有一个我知道的错误,那就是它fails when writing more than 26608 characters at once。通过限制在单个调用中传递的数据量很容易解决这个问题。

字体不是 Python 的问题,但编码才是。仅仅因为某些用户可能没有选择可以显示这些字符的字体而无法输出正确的字符是没有意义的。应该重新打开这个错误。

(为了完整起见,可以使用 Lucida Console 和 Consolas 以外的字体在控制台上显示 Unicode,但它是 requires a registry hack。) 希望对你有帮助。

【讨论】:

  • 我相信 WriteConsoleW 仅限于 UCS-2,即您不能使用辅助平面中的字符。但在大多数情况下,这应该不是问题。
猜你喜欢
  • 1970-01-01
  • 2018-07-05
  • 2019-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多