经过几次测试后,我设法限制了下面的最小test.py脚本中的错误功能:
# -*- coding: iso-8859-1 -*-
print u"Vérifier l'affichage de cette chaîne"
注意:test.py以ISO-8859-1(即latin-1)编码,即“é”等于“\ xe9”,“î”等于“\ xee”
D:\test>python --version
Python 2.7.3
D:\test>python test.py
Vérifier l'affichage de cette chaîne
D:\test>python test.py > test.log
Traceback (most recent call last):
File "test.py", line 2, in <module>
print u"VÚrifier l'affichage de cette cha¯ne"
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 1: ordinal not in range(128)
以下是问题:
在打印unicode字符串时,如果python的标准输出是转到控制台还是重定向或管道传输到其他字符串,那么python的行为是什么?
答案 0 :(得分:4)
首先,ISO-8859-1
不是有效的编码声明。你想要iso-8859-1
。如果您查看the docs,可以拨打latin_1
,iso-8859-1
,iso8859-1
,8859
,cp819
,latin
, latin1
或L1
,但不是ISO-8859-1
。
看起来codecs.lookup
向后弯曲以接受错误输入,包括执行不区分大小写的查找。如果您追踪codecs.lookup
到_codecs.lookup
到_PyCodec_Lookup
,则可以看到此评论:
/* Convert the encoding to a normalized Python string: all
characters are converted to lower case, spaces and hyphens are
replaced with underscores. */
但是源文件解码并没有经过相同的编解码器查找过程。因为它发生在编译时而不是运行时,所以没有理由这样做。 (无论如何,说&#34;它似乎有效,即使文档说它错了......那么为什么它不能正常工作?&#34;在第一个是愚蠢的的地方。)
要演示,如果我创建两个Latin-1文件:
badcode.py:
# -*- coding: ISO-8859-1 -*-
print u"Vérifier l'affichage de cette chaîne"
goodcode.py:
# -*- coding: iso-8859-1 -*-
print u"Vérifier l'affichage de cette chaîne"
第一个失败,第二个失败。
现在,为什么它&#34;工作&#34;什么时候它会进入控制台,但在管道输出时引发异常?
好吧,当你打印到Windows控制台或Unix TTY时,Python有一些代码试图猜测要使用的正确编码。 (我不确定Windows下的内容会发生什么;它甚至可能使用UTF-16输出,据我所知。)当你不打印到控制台/ TTY时,它可以&#39 ; t执行此操作,因此您必须明确指定编码。
通过查看sys.stdout.isatty()
,sys.stdout.encoding
和sys.getdefaultencoding()
,您可以看到一些正在发生的事情。这是我在不同情况下在Mac上看到的内容:
True, UTF-8, ascii, Vérifier
True, UTF-8, utf-8, Vérifier
False, None, ascii, UnicodeEncodeError
False, UTF-8, utf-8, Vérifier
如果isatty()
,encoding
将是TTY的适当编码;否则,encoding
将成为默认值,即2.x中的None
(意为ascii
),并且(我认为 - 我必须检查代码)基于3.x中的getdefaultencoding()
。这意味着,如果您尝试打印Unicode而stdout
不是2.x中的TTY,它会尝试将其编码为ascii
,strict
,如果您&#39将失败;有非ASCII字符。
如果您知道要使用哪种编解码器,可以通过检查isatty()
和编码到该编解码器(甚至ascii
,ignore
而不是{ {1}},如果您愿意,每当您打印时,而不是尝试打印Unicode。 (如果你知道你想要什么编解码器,你甚至可能想要这样做3.x-默认为UTF-8如果你试图生成Windows-1252文件那么太有帮助... )
那里的差异实际上与Latin-1无关。试试这个:
nocode.py:
strict
我的Mac终端编码为UTF-8的Unicode字符串,以及(显然)Windows-1252到我的Windows cmd窗口,但异常重定向到文件。
答案 1 :(得分:0)
因为我来到这里寻找“不要聪明”切换到python的print(),答案提供了只读变量的提示,这里是“make python相信stdout可以处理utf-8”片段:< / p>
import sys, codecs
# somewhere in the function you need it or global main():
sys.stdout = codecs.open('/dev/stdout', encoding='utf-8', mode='w', errors='strict')
在那里,现在python并不关心它是tty,tee(1),文件重定向还是只是cat(1)。