我在unicodes
上阅读了SO中的这篇高评价帖子
这里有一个例子:
$ python
>>> import sys
>>> print sys.stdout.encoding
UTF-8
>>> print 'xe9' # (1)
é
>>> print u'xe9' # (2)
é
>>> print u'xe9'.encode('latin-1') # (3)
é
>>>
并且解释为
(1)python按原样输出二进制字符串,终端接收它并尝试将其值与latin-1字符映射匹配。在latin-1中,0xe9或233产生字符"é",因此这就是终端显示的内容。
我的问题是:当encoding
是'UTF-8'
时,为什么终端与拉丁-1字符映射匹配?
当我尝试时
>>> print 'xe9'
?
>>> print u'xe9'
é
我得到的第一个结果与上面描述的不同。为什么会出现这种差异,latin-1
在这张照片中的作用在哪里?
您缺少一些重要的上下文;在这种情况下,OP将终端模拟器(Gnome终端)配置为将输出解释为Latin-1,但将shell变量设置为UTF-8。因此,shell告诉Python对Unicode输出使用UTF-8,但终端的实际配置是预期的Latin-1字节。
print
输出清楚地表明终端正在使用Latin-1解释输出,并且而不是使用UTF-8。
当终端设置为UTF-8时,xe9
字节不是有效的(不完整的)UTF-8,您的终端通常会打印一个问号:
>>> import sys
>>> sys.stdout.encoding
'UTF-8'
>>> print 'xe9'
?
>>> print u'xe9'
é
>>> print u'xe9'.encode('utf8')
é
如果您指示Python忽略这些错误,它会给您提供U+FFFD REPLACEMENT CHARACTER字形�
:
>>> 'xe9'.decode('utf8')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/mj/Development/venvs/stackoverflow-2.7/lib/python2.7/encodings/utf_8.py", line 16, in decode
return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode byte 0xe9 in position 0: unexpected end of data
>>> 'xe9'.decode('utf8', 'replace')
u'ufffd'
>>> print 'xe9'.decode('utf8', 'replace')
�
这是因为在UTF-8中,对于Unicode代码点U+9000到U+9FFF,xe9
是3字节编码的起始字节,如果仅打印为单个字节,则无效。这项工作:
>>> print 'xe9x80x80'
退
因为这是U+9000代码点的UTF-8编码,一个CJK象形文字字形。
如果你想了解编码和Unicode之间的区别,以及UTF-8和其他编解码器是如何工作的,我强烈建议你阅读:
Joel Spolsky 的绝对最小值每个软件开发人员绝对、积极地必须知道Unicode和字符集(没有借口!)
Python Unicode HOWTO
Ned Batchelder 的实用Unicode