【问题标题】:Which character encoding is the IPython terminal using?IPython 终端使用哪种字符编码?
【发布时间】: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


【解决方案1】:

IPython 像任何其他 Python 控制台程序一样在交互模式下使用 OEM 代码页:

In [1]: '\u2552'
ERROR - failed to write data to stream: <_io.TextIOWrapper name='<stdout>' mode=
'w' encoding='cp850'>
Out[1]:

In [2]: !chcp
Active code page: 850

如果安装了pyreadline,结果会发生变化(它会在 IPython 控制台中启用颜色等):

In [1]: '\u2552'
Out[1]: '╒'

In [2]: import sys

In [3]: sys.stdout.encoding
Out[3]: 'cp850'

In [4]: !chcp
Active code page: 850

一旦安装了pyreadline,IPython 的sys.displayhook 将结果写入使用WriteConsoleW() Windows Unicode API 的 readline 控制台对象,该 API 允许在当前代码页中打印甚至无法编码的 Unicode 字符(要查看它们,您可能需要在 Windows 控制台中配置(TrueType)字体,例如 Lucida Console)。

【讨论】:

    猜你喜欢
    • 2012-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-07
    • 2012-01-13
    • 1970-01-01
    相关资源
    最近更新 更多