【问题标题】:Why does python json decoder throw on a string with UTF-16 BOM?为什么 python json 解码器会抛出带有 UTF-16 BOM 的字符串?
【发布时间】:2018-04-30 19:11:37
【问题描述】:

挖掘python json解码器实现我注意到如果一个字符串被传递给json.loads并且它以\ufeff开头,这是一个UTF-16 BOM,它会引发一个JSONDecodeError

if isinstance(s, str):
    if s.startswith('\ufeff'):
        raise JSONDecodeError("Unexpected UTF-8 BOM (decode using utf-8-sig)", s, 0)

(github)

RFC3629(UTF-8 之一)说明了应禁止使用 UTF-16 BOM 的两种情况,但似乎都不适用于 JSON:

o 协议应该禁止使用 U+FEFF 作为签名 协议要求始终包含的文本协议元素 UTF-8,签名功能在那些中完全没用 案例。

o 协议也应该禁止使用 U+FEFF 作为签名 协议提供的那些文本协议元素 字符编码识别机制,当它是预期的 该协议的实现将能够 始终正确使用这些机制。这将是当 协议元素在控制下被严格维护 从创建时间到实施时间 他们的(正确标记的)传输。

RFC7159(JSON 那个)说:

JSON 文本应以 UTF-8、UTF-16 或 UTF-32 编码。这 默认编码为 UTF-8,JSON 文本以 UTF-8 编码 在它们将被成功读取的意义上是可互操作的 按最大实现数;有许多 无法成功读取其他文本的实现 编码(例如 UTF-16 和 UTF-32)。

所以在我看来应该允许使用 UTF-16。那么为什么 Python 会在这里引发呢?显然我错过了一些东西。

【问题讨论】:

  • 您似乎混淆了哪个 RFC 用于 UTF-8,哪个 RFC 用于 JSON。此外,Python 3 str 表示独立于编码的 Unicode。
  • 看多了就明白了。 python json解析器拒绝它在接受的答案中正确陈述的BOM的主要原因 - 规范允许它,所以这个解析器做到了。让我感到困惑的是,我认为有两个 BOM,UTF-8 和 UTF-16,解析器拒绝 UTF-16 一个,同时声明它拒绝 UTF-8 一个。实际上只有一个 BOM,U+FEFF,\xef\xbb\xbf 版本只是它的 UTF-8 编码。所以我现在理解的这段代码背后的逻辑是:[继续]
  • [cont.]:如果一个字符串以 BOM 开头,那么它必须是未剥离的 UTF-8 之一,因为如果它是 UTF-16 之一,它会在读取时被剥离。如果它幸存下来,那么源自传递字符串的字节将以 UTF-8 编码并在不剥离 BOM 的情况下进行解码。这就是为什么异常也会告诉“使用 utf-8-sig 解码”。

标签: python json encoding utf-8


【解决方案1】:

来自currently most recent JSON RFC

实现不得在网络传输的 JSON 文本的开头添加字节顺序标记 (U+FEFF)。为了互操作性,解析 JSON 文本的实现可能会忽略字节顺序标记的存在,而不是将其视为错误。

类似的语言也出现在RFC 7159

JSON 实现不需要接受字节顺序标记。 Python 的实现没有。如果您想将带有字节顺序标记的 JSON 传递给 Python 的 JSON 解析器,则应在较早的处理阶段删除 BOM。

【讨论】:

  • 这对我来说似乎是规格中的一个错误。 U+FEFF 的正式定义不是字节顺序标记,而是ZERO WIDTH NO-BREAK SPACE。 JSON 应该像对待任何其他空格一样对待它。
  • @MarkRansom:JSON 特别是singles out“无关紧要的空白”中允许的四个空白字符:空格、水平制表符、换行和回车。字符串之外的其他空格是错误的。
  • 是的,我认为空格列表是不必要的限制。如果你只打算使用它的 ASCII 子集,为什么还要基于 Unicode 呢?
  • 谢谢。这本身就回答了问题,但起初我仍然感到困惑。实际上,您在关于与编码无关的 Unicode 的原始问题下的评论有助于更清楚地解决问题! :)
猜你喜欢
  • 2014-04-22
  • 1970-01-01
  • 2010-11-15
  • 1970-01-01
  • 2020-01-18
  • 2017-07-15
  • 2014-01-18
  • 2014-06-21
  • 1970-01-01
相关资源
最近更新 更多