如何在 Python < 3 中将 UTF-8 编码文本打印到控制台?

Posted

技术标签:

【中文标题】如何在 Python < 3 中将 UTF-8 编码文本打印到控制台?【英文标题】:How to print UTF-8 encoded text to the console in Python < 3? 【发布时间】:2012-07-29 07:20:35 【问题描述】:

我正在运行一个最新的 Linux 系统,我的所有语言环境都是 UTF-8:

LANG=de_DE.UTF-8
LANGUAGE=
LC_CTYPE="de_DE.UTF-8"
LC_NUMERIC="de_DE.UTF-8"
LC_TIME="de_DE.UTF-8"
...
LC_IDENTIFICATION="de_DE.UTF-8"
LC_ALL=

现在我想将 UTF-8 编码的内容写入控制台。

目前 Python 使用 UTF-8 进行 FS 编码,但坚持使用 ASCII 作为默认编码:-(

>>> import sys
>>> sys.getdefaultencoding()
'ascii'
>>> sys.getfilesystemencoding()
'UTF-8'

我认为最好的(干净的)方法是设置PYTHONIOENCODING 环境变量。但似乎 Python 忽略了它。至少在我的系统上,我一直将ascii 作为默认编码,即使在设置了 envvar 之后也是如此。

# tried this in ~/.bashrc and ~/.profile (also sourced them)
# and on the commandline before running python
export PYTHONIOENCODING=UTF-8

如果我在脚本开始时执行以下操作,它仍然有效:

>>> import sys
>>> reload(sys)  # to enable `setdefaultencoding` again
<module 'sys' (built-in)>
>>> sys.setdefaultencoding("UTF-8")
>>> sys.getdefaultencoding()
'UTF-8'

但这种方法似乎不干净。那么,有什么好的方法可以做到这一点呢?

解决方法

而不是更改默认编码 - 这不是一个好主意(请参阅 mesilliac 的回答) - 我只是用 StreamWriter 包装 sys.stdout 像这样:

sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout)

请参阅 this gist 了解处理它的小实用函数。

【问题讨论】:

也许这会起作用:#!/usr/bin/env python # -- coding: utf-8 -- 记得把它放在源文件的最前面。 这只影响 Python 如何解释源代码中的文字字符串。 IO 编码仍然是 ASCII。 PYTHONIOENCODING 不会被忽略;只是,顾名思义,它是affects the encoding used for stdin/stdout/stderr,这不是您使用sys.getdefaultencoding() 检查的内容。 @Brutus:你是如何测试它不起作用的?它似乎对我有用。 python -c 'import sys; print sys.stdout.encoding' 提供UTF-8PYTHONIOENCODING='C' python -c 'import sys; print sys.stdout.encoding' 提供C 【参考方案1】:

似乎不建议这样做。

Fedora 建议using the system locale as the default, 但显然这会破坏其他东西。

这是mailing-list discussion的引述:

Python 中唯一支持的默认编码是: Python 2.x:ASCII Python 3.x:UTF-8 如果你改变这些,你就靠自己了,奇怪的事情会发生 开始发生。默认编码不仅影响 Python与外界的翻译,也 8 位字符串和 Unicode 之间的所有内部转换。 像 pango 模块中发生的事情(设置 通过重新加载站点模块,默认编码为“utf-8” 为了得到 sys.setdefaultencoding() API 回来)只是 彻头彻尾的错误,并且会导致严重的问题,因为 Unicode 对象缓存其默认编码表示。 请不要启用基于语言环境的默认编码。 如果您只想获得以下编码 stdout 和 stdin 正确设置管道,你应该 而是更改那些(仅)的 .encoding 属性。 -- 马克-安德烈·伦堡 eGenix.com

【讨论】:

【参考方案2】:

这就是我的做法:

#!/usr/bin/python2.7 -S

import sys
sys.setdefaultencoding("utf-8")
import site

注意手镯线中的-S。这告诉 Python 不会自动导入 site 模块。 site 模块用于设置默认编码并删除该方法,因此无法再次设置。但会尊重已经设置的内容。

【讨论】:

您能否根据 mesilliac 给出的答案对此进行扩展?它仍然正确吗? @Arafangion 我使用的方法发生在 Python 初始化的最开始。尚未创建缓存。我同意使用重新加载技巧是不好的。这是因为许多其他的东西可能已经被实例化或缓存了原始编码。因此,我想出了这种早期发生的方法。请注意,在它之前没有其他导入。它对我有用。 虽然这在测试中对我有用,但我决定避免使用它。只是不清楚我是否会遇到任何副作用并且闻起来有点腥;-) 我只是用默认编码将sys.stdout 包装在StreamWriter 中(至少在现代Linux系统中应该是UTF-8): sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout). 这是一个非常糟糕的主意。在过去的几周里,我解决了两个问题,这些问题通过从用户代码中删除 sys.setdefaultencoding("utf-8") 得到了解决。恕我直言,这只是掩盖了任何潜在的问题 @AlastairMcCormack 我使用它没有任何问题。只要你知道发生了什么,这不是问题。您认为它掩盖了哪些潜在问题?【参考方案3】:

如何在 Python

print u"some unicode text \NEURO SIGN"
print b"some utf-8 encoded bytestring \xe2\x82\xac".decode('utf-8')

即,如果您有一个 Unicode 字符串,则直接打印它。如果你有 一个字节串,然后先将其转换为 Unicode。

您的语言环境设置(LANGLC_CTYPE)指示 utf-8 语言环境和 因此(理论上)你可以直接打印一个 utf-8 字节串 应该在您的终端中正确显示(如果终端设置 与区域设置一致,它们应该是)但是你 应该避免它:不要硬编码你的字符编码 脚本中的环境; 改为直接打印 Unicode

您的问题中有许多错误的假设。

您不需要使用您的语言环境设置设置PYTHONIOENCODING, 将 Unicode 打印到终端。 utf-8 语言环境支持所有 Unicode 字符,即它按原样工作。

您不需要解决方法sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout)。有可能 如果某些代码(您无法控制)确实需要打印字节,则中断 和/或它可能会在 printing Unicode to Windows console (wrong codepage, can't print undecodable characters)。正确的语言环境设置和/或PYTHONIOENCODING envvar 就足够了。此外,如果您需要替换 sys.stdout,那么 use io.TextIOWrapper() instead of codecs module 就像 win-unicode-console package 一样。

sys.getdefaultencoding() 与您的区域设置无关 PYTHONIOENCODING。你假设设置PYTHONIOENCODING 应该更改sys.getdefaultencoding() 不正确。你应该 改为检查sys.stdout.encoding

sys.getdefaultencoding() 打印到 安慰。如果 stdout 是,它可以用作 Python 2 的后备 除非设置了PYTHOHIOENCODING,否则重定向到文件/管道:

$ python2 -c'import sys; print(sys.stdout.encoding)'
UTF-8
$ python2 -c'import sys; print(sys.stdout.encoding)' | cat
None
$ PYTHONIOENCODING=utf8 python2 -c'import sys; print(sys.stdout.encoding)' | cat
utf8

请勿拨打sys.setdefaultencoding("UTF-8");它可能会损坏您的 数据静默和/或破坏不期望的第 3 方模块 它。记住sys.getdefaultencoding()是用来转换字节串的 (str) 在 Python 2 中与unicode 之间的隐式 例如,"a" + u"b"。也可以看看, the quote in @mesilliac's answer.

【讨论】:

【参考方案4】:

如果程序没有在屏幕上显示适当的字符, 即,无效符号, 使用以下命令行运行程序:

PYTHONIOENCODING=utf8 python3 yourprogram.py

如果您的程序是全局安装的模块,则如下:

PYTHONIOENCODING=utf8 yourprogram

在某些平台上,如 Cygwin(mintty.exe 终端)和 Anaconda Python(或 Python 3),只需运行 export PYTHONIOENCODING=utf8 和 后来运行程序不行, 并且您每次都需要始终执行PYTHONIOENCODING=utf8 yourprogram 才能正确运行程序。

在 Linux 上,如果是 sudo,您可以尝试传递 -E 参数以将用户变量导出到 sudo 进程:

export PYTHONIOENCODING=utf8
sudo -E python yourprogram.py

如果您尝试此操作但没有成功,则需要在 sudo shell 上输入:

sudo /bin/bash
PYTHONIOENCODING=utf8 yourprogram

相关:

    How to print UTF-8 encoded text to the console in Python < 3? Changing default encoding of Python? Forcing UTF-8 over cp1252 (Python3) Permanently set Python path for Anaconda within Cygwin https://superuser.com/questions/1374339/what-does-the-e-in-sudo-e-do Why bash -c 'var=5 printf "$var"' does not print 5? https://unix.stackexchange.com/questions/296838/whats-the-difference-between-eval-and-exec

【讨论】:

utf8 区分大小写吗?此外,唯一可能的设置utf8 还是utf-8 也有效?只是因为我看到了这么多变体......(你在你的答案中使用了其中两个!?) 我认为至少对于我的 Python 3.7.2UTF-8 的使用不区分大小写,我不确定它是否忽略了 UTF-8 中的连字符。 这是有道理的——我使用的是 Python 2.7.X,但我不确定要使用什么......【参考方案5】:

虽然意识到 OP 问题是针对 Linux 的:当通过搜索引擎到达此处时,在 Windows 10 上,以下解决了该问题:

set PYTHONIOENCODING=utf8
python myscript.py

【讨论】:

以上是关于如何在 Python < 3 中将 UTF-8 编码文本打印到控制台?的主要内容,如果未能解决你的问题,请参考以下文章

如何在Python中将符号如●打印到文件中

在Python中将文本附加到文件[重复]

如何在Python中将字符串转换为数据框[重复]

如何在python中将集合转换为列表?

在 SWIG 中将结构从 C++ 函数返回到 Python

如何在 C# 中将“=?utf-8?B?...?=”解码为字符串