nos*_*klo 6 python unicode encoding
我首先创建一个字符串变量,其中包含一些非ascii utf-8编码数据:
>>> text = 'á'
>>> text
'\xc3\xa1'
>>> text.decode('utf-8')
u'\xe1'
Run Code Online (Sandbox Code Playgroud)
使用unicode()它会引发错误......
>>> unicode(text)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0:
ordinal not in range(128)
Run Code Online (Sandbox Code Playgroud)
...但如果我知道编码,我可以将它用作第二个参数:
>>> unicode(text, 'utf-8')
u'\xe1'
>>> unicode(text, 'utf-8') == text.decode('utf-8')
True
Run Code Online (Sandbox Code Playgroud)
现在,如果我有一个在该__str__()方法中返回此文本的类:
>>> class ReturnsEncoded(object):
... def __str__(self):
... return text
...
>>> r = ReturnsEncoded()
>>> str(r)
'\xc3\xa1'
Run Code Online (Sandbox Code Playgroud)
unicode(r)似乎使用str()它,因为它引起了与unicode(text)上面相同的错误:
>>> unicode(r)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0:
ordinal not in range(128)
Run Code Online (Sandbox Code Playgroud)
到现在为止一切都按计划进行!
但正如没有人会想到的那样,unicode(r, 'utf-8')甚至不会尝试:
>>> unicode(r, 'utf-8')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: coercing to Unicode: need string or buffer, ReturnsEncoded found
Run Code Online (Sandbox Code Playgroud)
为什么?为什么这种不一致的行为?这是一个错误吗?是打算吗?很尴尬.
这种行为确实令人困惑,但具有内涵.我在这里重现了Python内置函数文档中的整个unicode文档(对于版本2.5.2,我写这篇文章):
unicode([object [,encoding [,errors]]])
使用以下模式之一返回对象的Unicode字符串版本:
如果给出了编码和/或错误,unicode()将使用编解码器解码对象,该对象可以是8位字符串或字符缓冲区.encoding参数是一个给出编码名称的字符串; 如果编码未知,则引发LookupError.错误处理是根据错误完成的; 这指定了对输入编码中无效的字符的处理.如果错误是'strict'(默认值),则会在错误时引发ValueError,而'ignore'的值会导致错误被忽略,而'replace'的值会导致官方的Unicode替换字符U + FFFD,用于替换无法解码的输入字符.另请参阅编解码器模块.
如果没有给出可选参数,unicode()将模仿str()的行为,除了它返回Unicode字符串而不是8位字符串.更确切地说,如果object是Unicode字符串或子类,它将返回该Unicode字符串,而不应用任何其他解码.
对于提供__unicode __()方法的对象,它将调用此方法而不使用参数来创建Unicode字符串.对于所有其他对象,请求8位字符串版本或表示,然后使用"严格"模式下的默认编码的编解码器将其转换为Unicode字符串.
2.0版中的新功能.在2.2版中更改:添加了对__unicode __()的支持.
因此,当您调用时unicode(r, 'utf-8'),它需要一个8位字符串或一个字符缓冲区作为第一个参数,因此它使用该__str__()方法强制您的对象,并尝试使用utf-8编解码器对其进行解码.没有utf-8,unicode()函数__unicode__()在你的对象上寻找一个方法,而不是找到它,调用__str__(),按照您的建议方法,尝试使用默认编解码器转换为unicode.
unicode不会猜测您的文本的编码。如果您的对象可以将自身打印为unicode,请定义__unicode__()返回 Unicode 字符串的方法。
秘密在于它unicode(r)实际上并没有__str__()自称。相反,它正在寻找一种__unicode__()方法。的默认实现__unicode__()将调用__str__(),然后尝试使用ascii字符集对其进行解码。当您传递编码时,unicode()期望第一个对象是可以解码的东西——即basestring.
行为很奇怪,因为如果我不通过“utf-8”,它会尝试解码为 ascii。但是如果我通过'utf-8'它会给出一个不同的错误......
那是因为当您指定“utf-8”时,它会将第一个参数视为要解码的类似字符串的对象。如果没有它,它会将参数视为要强制为 unicode 的对象。
我不明白这种混乱。如果您知道对象的text属性将始终是 UTF-8 编码,只需定义__unicode__(),然后一切都会正常工作。