【问题标题】:Print unicode characters to terminal in utf-8以 utf-8 将 unicode 字符打印到终端
【发布时间】:2021-05-14 22:43:03
【问题描述】:

我使用 Python 3.9.1 和 Linux (CentOS 7)。我想将 unicode 字符打印到控制台。我想用 UTF-8 做所有事情。如果我打开 python 交互式控制台并写:

print("├")

一切顺利,打印出来:

现在我将同一行 print("├") 放在一个文件中,然后使用 UTF-8 编码(Linux 上的默认值)保存文件。 然后我收到以下错误:

UnicodeEncodeError: 'latin-1' codec can't encode character '\u251c' in position 0: ordinal not in range(256)

“latin-1”从何而来?

我还在第一行强制使用 UTF-8(无论如何这应该是 Python3 中的默认值)

# coding: utf8

但它不会改变任何东西。

更多关于什么有效和什么无效的信息:

s = "├"
#print(s) # FAIL
s2 = s.encode('utf8')
print(s2) # prints b'\xe2\x94\x9c'
print(s2.decode('latin-1')) # prints the right thing

这里发生了什么?我可以在脚本中获得与交互式控制台中相同的行为吗?

【问题讨论】:

  • 我假设您使用的是 Windows?
  • 看起来,当您运行脚本时,它会打印到使用latin-1 编码的环境中? IE。运行脚本的控制台窗口未使用 UTF-8 编码?
  • 我不太明白,print(s2.decode('latin-1')) 不应该打印正确的东西,因为 s2 是 utf-8 编码的。
  • 检查环境变量PYTHONIOENCODING的值。
  • LANG 环境变量设置为什么?

标签: python python-3.x utf-8


【解决方案1】:

s = "├"(在您的 UTF-8 编码源文件中)将字符 \u251C 分配给 UTF-8 编码字符串 s 的第一个位置。

print(s) 失败,因为此处的 print 将表示 s 的字节发送到标准输出,标准输出需要 latin-1 编码。实际上,s.encode('latin-1') 之类的内容会失败,因为字符串中的第一个字符无法正确编码。

如果您直接运行该语句 (s.encode('latin-1')),您会发现它会导致相同的错误。

s2 = s.encode('utf8') 工作得很好,它告诉 Python 将 s 的内容显式编码为字节序列。 s2 现在使用 UTF-8 编码保存 s 的字节编码。 (也许 'b' 会是一个更好的变量名,毕竟它不是字符串)

print(s2) 确实打印了b'\xe2\x94\x9c',因为它只是打印了一个字节序列的 Python 表示。它不是一个字符串,所以你得到了打印值的表示。它应该是你可以用来定义s2 的文字,即s2 = b'\xe2\x94\x9c' 不会改变任何东西。

print(s2.decode('latin-1')) 打印正确的东西有点神秘。 s2 是 U+251C 字符的正确 UTF-8 字节序列 (https://www.fileformat.info/info/unicode/char/251c/index.htm)

显然,您的 Python 获取了 s2.decode('latin-1') 的结果,再次将其编码为 latin-1 字节序列,然后将其写入输出流,并在其中为您正确呈现。

由于 Python 会对尝试打印 UTF-8 编码字符串的早期打印语句执行相同的操作,因此它解释了为什么这些语句不能正确显示(或根本不正确)。

解决方案是明确告诉 Python 将标准输出的编码覆盖为 UTF-8,因此您可以打印 UTF-8 字符串,而无需 Python 尝试将其编码为 latin-1 编码字节序列(这将失败)。

正如此处记录的https://docs.python.org/3/using/cmdline.html#envvar-PYTHONIOENCODING,您可以通过设置SET PYTHONENCODING=UTF-8 来做到这一点。相反,如果您想在交互式环境中复制问题,您可能可以通过PYTHONLEGACYWINDOWSSTDIO 获得该行为。

何时何地进行设置取决于您的系统环境。其他应用程序是否依赖较旧的脚本或其他版本的 Python 不这样做?如果没有,可以考虑设置一个全局系统环境变量。或者,您可以在执行脚本之前设置它,即在运行它的批处理文件中。

【讨论】:

  • 他们很清楚这是一个Linux环境,所以我认为PYTHONLEGACYWINDOWSSTDIO不会有什么不同。
【解决方案2】:

原因是我的LANG 环境变量设置为en_US,而它应该是en_US.UTF-8

解决问题的另一种方法是将PYTHONENCODING 设置为UTF-8(对我来说是空的)。

我仍然不完全理解为什么 Python 只对非交互式脚本感到困惑......

更多详情:https://simulrpi.readthedocs.io/en/latest/display_problems.html

【讨论】:

  • 在交互式提示和脚本中尝试 import sys;print(sys.stdin.encoding,sys.stdout.encoding) 与您原来的 LANG 设置,以查看 Python 在每种情况下默认使用的编码。也可以设置PYTHONUTF8=1开启UTF-8模式。
猜你喜欢
  • 2017-01-15
  • 2012-01-13
  • 1970-01-01
  • 1970-01-01
  • 2014-06-18
  • 1970-01-01
  • 2020-06-04
  • 2015-03-17
  • 2021-01-09
相关资源
最近更新 更多