【发布时间】:2015-11-27 15:35:50
【问题描述】:
我曾经认为我已经很清楚整个编码的东西了。我似乎错了,因为我无法解释这里发生了什么。
我试图做的是使用tabulate 模块来打印格式良好的表格
from tabulate import tabulate
s = tabulate([[1,2],[3,4]], ["x","y"], tablefmt="fancy_grid")
print(s)
在 Windows 10 下的 IPython 3.5.0 的交互式控制台中。我预计结果是
╒═════╤═════╕
│ x │ y │
╞═════╪═════╡
│ 1 │ 2 │
├─────┼─────┤
│ 3 │ 4 │
╘═════╧═════╛
但是,我得到了一个
UnicodeEncodeError: 'charmap' codec can't encode character '\u2552' in position 0: character maps to <undefined>
一头雾水,我试图找出问题出在哪里,并查看了字符串的repr:
In [15]: s
Out[15]: '╒═════╤═════╕\n│ x │ y │\n╞═════╪═════╡\n│ 1 │ 2 │\n├─────┼─────┤\n│ 3 │ 4 │\n╘═════╧═════╛'
嗯,所有字符都可以在终端显示(甚至是第一个触发错误的字符)。
只是检查一些细节:
In [16]: sys.stdout.encoding
Out[16]: 'cp850'
In [17]: s.encode("cp850")
[...]
UnicodeEncodeError: 'charmap' codec can't encode character '\u2552' in position 0: character maps to <undefined>
那么是终端使用的是哪种编码方式呢? Python 说它是cp850,它告诉我cp850 没有╒ 字符(which is true,它是cp437 中必须为重音字母腾出空间的字符之一),但是我可以在终端窗口中看到它!
更复杂的是,当使用本机 Python 控制台而不是 IPython 时,错误似乎更容易理解:
>>> s
'\u2552═══\u2564═══\u2555\n│ 1 │ 2 │\n├───┼───┤\n│ 3 │ 4 │\n\u2558═══\u2567═══\u255b'
>>> sys.stdout.encoding
'cp850'
>>> print(s)
Traceback (most recent call last):
[...]
UnicodeEncodeError: 'charmap' codec can't encode character '\u2552' in position 0: character maps to <undefined>
所以至少 Python 是一致的,但是 IPython 发生了什么?
【问题讨论】:
-
如果您看到的是 cp437 字符,但 Python 说的是 cp850,那么 Python 就是不一致的那个。找出控制台的实际设置(例如参见What encoding/code page is cmd.exe using)。
-
@ThomasDickey:我看到 both - 像
'╒Í'这样的字符串,其中包含两个字符集独有的字符(╒仅在cp437和Í只有在cp850) 中才能正确显示... -
我可以在 IPython 中重复这个结果。 IPython 中的
repr应该与直接运行 Python 的repr相同,但事实并非如此。 -
Windows 控制台实际上能够使用 unicode API 显示更广泛的字符,但
print()和sys.stdout仍然使用字节 API,它只能处理活动代码中的字符页。 win_unicode_console 包试图解决这个问题。我猜 IPython 在你显示s时会找到不同的默认编码 - 尝试导入IPython.utils.encoding.DEFAULT_ENCODING看看它发现了什么。
标签: python unicode terminal ipython codepages