如何在 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-8
,PYTHONIOENCODING='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。
您的语言环境设置(LANG
、LC_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.2
,UTF-8
的使用不区分大小写,我不确定它是否忽略了 UTF-8 中的连字符。
这是有道理的——我使用的是 Python 2.7.X
,但我不确定要使用什么......【参考方案5】:
虽然意识到 OP 问题是针对 Linux 的:当通过搜索引擎到达此处时,在 Windows 10 上,以下解决了该问题:
set PYTHONIOENCODING=utf8
python myscript.py
【讨论】:
以上是关于如何在 Python < 3 中将 UTF-8 编码文本打印到控制台?的主要内容,如果未能解决你的问题,请参考以下文章