以utf-16be编码并以utf-8解码打印正确的输出但无法转换为Python表示?

问题描述 投票:0回答:1

如果我使用

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))

我知道编码字符串应该使用相同的编码进行解码,但为什么这种行为是我想要理解的?我想知道:

  1. 为什么使用

    str
      编码
    utf-16be
    并使用
    encoded_str
    解码
    utf-8
      不会导致错误?

  2. 由于编码和解码不会导致错误,并且

    decoded_str
    是有效的 JSON(通过 print 语句可以看出),为什么
    decode(decoded_str)
    会导致错误?

  3. 为什么将输出写入文件并通过

    less
    命令查看文件将其显示为二进制文件?

    file = open("data.txt", 'w')
    file.write(decoded_str)
    

    使用

    less
    命令查看
    data.txt
    时:

    "data.txt" may be a binary file.  See it anyway?
    
  4. 如果

    decoded_str
    是无效的JSON或其他内容,我如何以原始形式查看它(
    print()
    将其打印为有效的JSON)

我在

Python 3.10.12
 上使用 
Ubuntu 22.04.4 LTS

python json encoding decoding utf
1个回答
0
投票
  1. 为什么用utf-16be编码str并用utf-8解码encoded_str不会导致错误?

因为在这种情况下,

str.encode("utf-16be")
的结果字节也是有效的UTF-8。事实上,对于 ASCII 字符来说总是如此,您确实需要超越 U+007F 才能在此处触发可能的错误(例如,使用字符串
str = '{"foo": "!"}'
(这是一个全角感叹号,U+FF01)。

  1. 既然编码和解码不会导致错误,并且decoded_str是一个有效的JSON(通过print语句可以看出),为什么decode(decoded_str)会导致错误?

仅仅因为可以打印字符串并不意味着它就是有效的 JSON。特别是由于编码为 UTF-16,添加了一堆空字节。例如,UTF-16BE 中的

f
0x0066
。这些字节在 UTF-8 中重新编码时实际上构成两个字符,
f
和空字符
0x00
。根据我对 JSON 规范的阅读,不允许使用空字符,这就是
decode(decoded_str)
失败的原因。

  1. 为什么将输出写入文件并通过 less 命令查看文件显示为二进制文件?

可能又是那些空字节。由于存在大量空字节,

less
可能会标记它可能是一个二进制文件,因为这在 UTF-8 中相对不常见(与 UTF-16 相比,Linux 更喜欢 UTF-8)

  1. 如果解码的_str是无效的JSON或其他内容,我如何以原始形式查看它(print()将其打印为有效的JSON)

这里有太多可能的答案,这实际上取决于这里的真实用例。最快的方法就是不要使用不同的编码进行编码/解码。下一个最快的是反转编码/解码过程,尽管这对于所有字符串或编码可能性来说并不是无损的,特别是在处理 UTF-16 + UTF-8 混合时的代理范围。

© www.soinside.com 2019 - 2024. All rights reserved.