Python-解码的unicode字符串不会保持解码状态

时间:2019-01-11 01:25:51

标签: python unicode

对于我来说仍然无法进行编程可能已经太晚了(很抱歉,如果这很愚蠢,我很抱歉),但是我发现在Python中使用字符串解码有一种奇怪的行为:

>>> bs = bytearray(b'I\x00n\x00t\x00e\x00l\x00(\x00R\x00)\x00')
>>> name = bs.decode("utf-8", "replace")
>>> print(name)
I n t e l ( R )
>>> list_of_dict = []
>>> list_of_dict.append({'name': name})
>>> list_of_dict
[{'name': 'I\x00n\x00t\x00e\x00l\x00(\x00R\x00)\x00'}] 

如果列表已被解码,该列表如何包含Unicode字符?

2 个答案:

答案 0 :(得分:1)

按定义对字节进行解码会产生“ Unicode”(实际上是文本,在这里Unicode是您存储任意文本的方式,因此Python在内部将其用于所有文本),因此当您说“列表如何包含Unicode字符时,已经被解码了吗?”它背叛了对Unicode的根本误解。如果您在Python 3中有一个str,它就是文本,并且该文本由一系列Unicode代码点组成(具有未指定的内部编码;实际上,现代Python以ASCII,latin-1,UCS-2存储或UCS-4,具体取决于最高序号值,有时还会缓存UTF-8表示形式或本机wchar表示形式以用于旧版扩展模块)。

您正在看到nul字符的repr(Unicode序数0),并认为它没有正确解码,并且您很可能是对的(nul字符没有什么不合法的地方,它们只是没有纯文本中常见);您的输入数据几乎可以肯定是以UTF-16-LE而不是UTF-8编码的。使用正确的编解码器,文本将正确显示:

>>> bs = bytearray(b'I\x00n\x00t\x00e\x00l\x00(\x00R\x00)\x00')
>>> bs.decode('utf-16-le')  # No need to replace things, this is legit UTF-16-LE
'Intel(R)'
>>> list_of_dict = [{'name': _}]
>>> list_of_dict
[{'name': 'Intel(R)'}]

要点是,尽管生成nul字符是合法的,除非它是二进制文件,否则很可能没有任何东西,如果要获取它们,您可能选择了错误的编解码器。

打印str与显示之间的差异是list / dict的一部分,这是因为list / dict与{{1 }}的内容(在许多情况下,您会键入以编程方式重现该对象的内容),因此使用repr转义符来呈现字符串。 \x00直接print不涉及str,因此nul字符被呈现为空格(因为nul没有可打印的字符,因此您的终端选择将其呈现为空格)。

答案 1 :(得分:1)

所以我认为正在发生的事情是,以空结尾的字符\x00未被正确解码,并且在解码后仍保留在字符串中。但是,由于这些是空字符,因此当您打印将其解释为无或为空的字符串时,它们不会弄乱(在我的情况下,我在arch linux的python2和python3上测试了您的代码,它们被完全省略了)

现在的问题是,使用utf-8解码时,每个字符串字符都有一个\x00字符,所以这意味着您的字节流实际上是16位字符而不是8位字符。因此,如果您尝试使用utf-16进行解码,则您的代码将像超级字符一样工作:)

>>> bs = bytearray(b'I\x00n\x00t\x00e\x00l\x00(\x00R\x00)\x00')
>>> t = bs.decode("utf-16", "replace")
>>> print(t)
Intel(R)
>>> t
'Intel(R)'