如果我使用
utf-16be
编码字符串并使用 utf-8
解码编码字符串,我不会收到任何错误,并且输出似乎也正确打印在屏幕上,但我仍然无法使用 json 模块将解码后的字符串转换为 Python 表示形式。
import json
str = '{"foo": "bar"}'
encoded_str = str.encode("utf-16be")
decoded_str = encoded_str.decode('utf-8')
print(decoded_str)
print(json.JSONDecoder().decode(decoded_str))
我知道编码字符串应该使用相同的编码进行解码,但为什么这种行为是我想要理解的?我想知道:
为什么使用
str
编码 utf-16be
并使用 encoded_str
解码 utf-8
不会导致错误?
由于编码和解码不会导致错误,并且
decoded_str
是有效的 JSON(通过 print 语句可以看出),为什么 decode(decoded_str)
会导致错误?
为什么将输出写入文件并通过
less
命令查看文件将其显示为二进制文件?
file = open("data.txt", 'w')
file.write(decoded_str)
使用
less
命令查看data.txt
时:
"data.txt" may be a binary file. See it anyway?
如果
decoded_str
是无效的JSON或其他内容,我如何以原始形式查看它(print()
将其打印为有效的JSON)
我在
Python 3.10.12
上使用
Ubuntu 22.04.4 LTS
- 为什么用utf-16be编码str并用utf-8解码encoded_str不会导致错误?
因为在这种情况下,
str.encode("utf-16be")
的结果字节也是有效的UTF-8。事实上,对于 ASCII 字符来说总是如此,您确实需要超越 U+007F 才能在此处触发可能的错误(例如,使用字符串 str = '{"foo": "!"}'
(这是一个全角感叹号,U+FF01)。
- 既然编码和解码不会导致错误,并且decoded_str是一个有效的JSON(通过print语句可以看出),为什么decode(decoded_str)会导致错误?
仅仅因为可以打印字符串并不意味着它就是有效的 JSON。特别是由于编码为 UTF-16,添加了一堆空字节。例如,UTF-16BE 中的
f
是 0x0066
。这些字节在 UTF-8 中重新编码时实际上构成两个字符,f
和空字符 0x00
。根据我对 JSON 规范的阅读,不允许使用空字符,这就是 decode(decoded_str)
失败的原因。
- 为什么将输出写入文件并通过 less 命令查看文件显示为二进制文件?
可能又是那些空字节。由于存在大量空字节,
less
可能会标记它可能是一个二进制文件,因为这在 UTF-8 中相对不常见(与 UTF-16 相比,Linux 更喜欢 UTF-8)
- 如果解码的_str是无效的JSON或其他内容,我如何以原始形式查看它(print()将其打印为有效的JSON)
这里有太多可能的答案,这实际上取决于这里的真实用例。最快的方法就是不要使用不同的编码进行编码/解码。下一个最快的是反转编码/解码过程,尽管这对于所有字符串或编码可能性来说并不是无损的,特别是在处理 UTF-16 + UTF-8 混合时的代理范围。