我在python 2.7.2中理解unicode时遇到问题,所以我在空闲时尝试了一些测试。有两件事被标记为“不确定”。请告诉我他们失败的原因。至于其他项目,请告诉我我的评论是否准确。
>>> s
'Don\x92t ' # s is a string
>>> u
u'Don\u2019t ' # u is a unicode object
>>> type(u) # confirm u is unicode
<type 'unicode'>
>>> type(s) # confirm s is string
<type 'str'>
>>> type(s) == 'str' # wrong way to test
False
>>> isinstance(s, str) # right way to test
True
>>> print s
Don’t # works because idle can handle strings
>>> print u
Don’t # works because idle can handle unicode
>>> open('9', 'w').write(s.encode('utf8')) #encode takes unicode, but s is a string,
# so this fails
Traceback (most recent call last):
File "<pyshell#28>", line 1, in <module>
open('9', 'w').write(s.encode('utf8'))
UnicodeDecodeError: 'ascii' codec can't decode byte 0x92 in position 3: ordinal not in range(128)
>>> open('9', 'w').write(s) # write can write strings
>>> open('9', 'w').write(u) # write can't write unicode
Traceback (most recent call last):
File "<pyshell#30>", line 1, in <module>
open('9', 'w').write(u)
UnicodeEncodeError: 'ascii' codec can't encode character u'\u2019' in position 3: ordinal not in range(128)
>>> open('9', 'w').write(u.encode('utf8')) # encode turns unicode to string, which write can handle
>>> open('9', 'w').write(s.decode('utf8')) # decode turns string to unicode, which write can't handle
Traceback (most recent call last):
File "<pyshell#32>", line 1, in <module>
open('9', 'w').write(s.decode('utf8'))
File "C:\program files\Python27\lib\encodings\utf_8.py", line 16, in decode
return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode byte 0x92 in position 3: invalid start byte
>>> e = '{}, {}'.format(s, u) # fails becase ''.format is string, while u is unicode
Traceback (most recent call last):
File "<pyshell#33>", line 1, in <module>
e = '{}, {}'.format(s, u)
UnicodeEncodeError: 'ascii' codec can't encode character u'\u2019' in position 3: ordinal not in range(128)
>>> e = '{}, {}'.format(s, u.encode('utf8')) # works because u.encode is a string
>>> e = u'{}, {}'.format(s, u) # not sure
Traceback (most recent call last):
File "<pyshell#36>", line 1, in <module>
e = u'{}, {}'.format(s, u)
UnicodeDecodeError: 'ascii' codec can't decode byte 0x92 in position 3: ordinal not in range(128)
>>> e = u'{}, {}'.format(s.decode('utf8'), u) # not sure
Traceback (most recent call last):
File "<pyshell#55>", line 1, in <module>
e = u'{}, {}'.format(s.decode('utf8'), u)
File "C:\program files\Python27\lib\encodings\utf_8.py", line 16, in decode
return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode byte 0x92 in position 3: invalid start byte
>>> e = '\n'.join([s, u]) # wants strings, but u is unicode
Traceback (most recent call last):
File "<pyshell#37>", line 1, in <module>
e = '\n'.join([s, u])
UnicodeDecodeError: 'ascii' codec can't decode byte 0x92 in position 3: ordinal not in range(128)
>>> e = '\n'.join([s, u.encode('utf8')]) # u.encode is now a string
答案 0 :(得分:2)
首先s
不是utf-8
编码的字符串,可能是cp1250
编码的字符串。因此,使用utf-8
对其进行解码始终会失败。
>>> e = u'{}, {}'.format(s, u) # not sure
首先“不确定”是因为u'{}, {}'
是unicode
并尝试将format
函数的每个参数编码为unicode
字符串。但由于它不知道s
编码的内容,因此假设s
被编码为ascii
,因此它会尝试将其解码为ascii
(基本上正在做s.decode('ascii')
)并失败,因为s
是cp1250
编码的字符串。
>>> e = u'{}, {}'.format(s.decode('utf8'), u) # not sure
第二个失败是因为您尝试将其解码为utf-8
但实际上,如前所述,其他一些编码与utf-8
不兼容。
答案 1 :(得分:1)
Python 2将自动编码Unicode值,或在混合字符串和unicode操作时解码字符串值。这就是你的困惑所在。
例如,在将Unicode值写入文件时,Python 2将尝试将该值编码为字符串。由于未指定编码,因此使用默认编码,而Python 2上的编码是ASCII。在unicode上下文中使用str
值也是如此,Python 2将使用ASCII编解码器对其进行解码。
但是,您的示例值包含无法表示为ASCII字符的代码点或字节,因此自动转换失败。您看到的UnicodeEncodeError
或UnicodeDecodeError
例外是自动转化的结果。
具体来说,e = u'{}, {}'.format(s, u)
尝试将s
解码为Unicode,以将其插入到unicode u'{}, {}'
模板字符串中。
为避免自动转换,您需要使用显式转换。要使用显式转换,您需要知道用于字节字符串的正确编码,或者在编码unicode时使用的编解码器。
您的计算机是 Windows 计算机,配置为使用类似Latin-1的代码页,1250或1252代码页。这就是为什么在将该字节直接写入终端时打印\x92
字节会打印’
。
Python知道您的计算机配置了该代码页,如果您打印sys.stdout.encoding
,您会看到cp1250
或cp1252
或类似的打印。这就是为什么Python知道如何打印Unicode值,并且在打印’
代码点时会看到\u2019
字符。
然而,您的s
值不以UTF-8编码。尝试从 UTF8解码该值将因此失败。您需要从cp1252
解码:
>>> '\x92'.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 0x92 in position 0: invalid start byte
>>> '\x92'.decode('cp1252')
u'\u2019'
如果您使用u'{}, {}'.format(s.decode('cp1252'), u)
,则不会抛出任何异常,因为s
可以正确解码为Unicode。