我在Ubuntu终端(编码设置为utf-8)中运行此代码段两次,一次使用./test.py
,然后使用./test.py >out.txt
:
uni = u"\u001A\u0BC3\u1451\U0001D10C"
print uni
没有重定向,它会打印垃圾。通过重定向,我得到了一个UnicodeDecodeError。有人可以解释为什么我只在第二种情况下得到错误,或者甚至更好地详细解释两种情况下幕后发生的事情?
答案 0 :(得分:246)
答案 1 :(得分:19)
Python在写入终端,文件,管道等时总是编码Unicode字符串。当写入终端时,Python通常可以确定终端的编码并正确使用它。在写入文件或管道时,Python默认为'ascii'编码,除非另有明确说明。通过PYTHONIOENCODING
环境变量管道输出时,可以告诉Python该做什么。 shell可以在将Python输出重定向到文件或管道之前设置此变量,以便知道正确的编码。
在您的情况下,您打印了4个不常见的字符,终端不支持其字体。这里有一些例子来帮助解释行为,我的终端实际支持的字符(使用cp437,而不是UTF-8)。
请注意,#coding
注释表示保存源文件的编码。我选择了utf8所以我可以支持我的终端无法支持的源代码。编码重定向到stderr,以便在重定向到文件时可以看到。
#coding: utf8
import sys
uni = u'αßΓπΣσµτΦΘΩδ∞φ'
print >>sys.stderr,sys.stdout.encoding
print uni
cp437
αßΓπΣσµτΦΘΩδ∞φ
Python正确地确定了终端的编码。
None
Traceback (most recent call last):
File "C:\ex.py", line 5, in <module>
print uni
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-13: ordinal not in range(128)
Python无法确定编码(无),因此使用'ascii'默认值。 ASCII仅支持转换Unicode的前128个字符。
cp437
我的输出文件是正确的:
C:\>type out.txt
αßΓπΣσµτΦΘΩδ∞φ
现在我将在源码中输入一个我的终端不支持的字符:
#coding: utf8
import sys
uni = u'αßΓπΣσµτΦΘΩδ∞φ马' # added Chinese character at end.
print >>sys.stderr,sys.stdout.encoding
print uni
cp437
Traceback (most recent call last):
File "C:\ex.py", line 5, in <module>
print uni
File "C:\Python26\lib\encodings\cp437.py", line 12, in encode
return codecs.charmap_encode(input,errors,encoding_map)
UnicodeEncodeError: 'charmap' codec can't encode character u'\u9a6c' in position 14: character maps to <undefined>
我的终端不明白最后一个汉字。
cp437
αßΓπΣσµτΦΘΩδ∞φ?
可以使用编码指定错误处理程序。在这种情况下,未知字符被?
替换。 ignore
和xmlcharrefreplace
是其他一些选项。当使用UTF8(支持编码所有Unicode字符)时,将永远不会进行替换,但用于显示字符的 font 仍必须支持它们。
答案 2 :(得分:12)
打印时对其进行编码
uni = u"\u001A\u0BC3\u1451\U0001D10C"
print uni.encode("utf-8")
这是因为当您手动运行脚本时,python会在将其输出到终端之前对其进行编码,当您管道时,python不对其进行编码,因此您在进行I / O时必须手动编码。