【问题标题】:Python can't encode with surrogateescapePython 无法使用 surrogateescape 进行编码
【发布时间】:2015-11-01 02:46:48
【问题描述】:

我对 Python (3.4) 中的 Unicode 代理编码有疑问:

>>> b'\xCC'.decode('utf-16_be', 'surrogateescape').encode('utf-16_be', 'surrogateescape')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'utf-16-be' codec can't encode character '\udccc' in position 0: surrogates not allowed

如果我没记错的话,根据Python documentation

'surrogateescape':解码时,用单个代理替换字节 代码范围从 U+DC80 到 U+DCFF。然后此代码将被退回 使用“surrogateescape”错误处理程序时进入相同的字节 编码数据时。

代码应该只生成源序列 (b'\xCC')。那么为什么会引发异常呢?

这可能与我的第二个问题有关:

在 3.4 版中更改:utf-16* 和 utf-32* 编码器不再允许对代理代码点 (U+D800–U+DFFF) 进行编码。

(来自https://docs.python.org/3/library/codecs.html#standard-encodings

据我所知,如果没有代理对,就不可能将某些代码点编码为 UTF-16。那么这背后的原因是什么呢?

【问题讨论】:

    标签: python unicode utf-16 surrogate-pairs


    【解决方案1】:

    进行此更改是因为 Unicode 标准 明确禁止此类编码。请参阅 issue #12892,但显然 surrogateescape 错误处理程序无法与 UTF-16 或 UTF-32 一起使用,因为这些编解码器不兼容 ASCII。

    具体来说:

    我用编码器测试了 utf_16_32_surrogates_4.patch: surrogateescape 没有按预期工作。

    >>> b'[\x00\x80\xdc]\x00'.decode('utf-16-le', 'ignore')
    '[]'
    >>> b'[\x00\x80\xdc]\x00'.decode('utf-16-le', 'replace')
    '[�]'
    >>> b'[\x00\x80\xdc]\x00'.decode('utf-16-le', 'surrogateescape')
    '[\udc80\udcdc\uffff'
    

    => 我期待'[\udc80\udcdc]'

    得到了回应:

    是的,surrogateescape 不适用于 ASCII 不兼容的编码并且不能。首先,它不能代表从 utf-16-le 解码 b'\x00\xd8' 或从 utf-32* 解码 b'ABCD' 的结果。这个问题值得在 Python-Dev 上单独 issue(甚至 PEP)和讨论。

    我相信surrogateescape 处理程序更适用于 UTF-8 数据;解码为 UTF-16 或 UTF-32 现在也可以使用它是一个很好的附加功能,但显然它不能在另一个方向上工作。

    【讨论】:

    • 为什么surrogateescape 不能使用 ASCII 不兼容的编码?此外,您指出“首先,它不能代表解码b'\x00\xd8' 的结果”,但根据 PEP 383,这不是正确的单独代理,在我的示例中,.decode() 方法会产生正确的单独代理,所以 @987654331 @ 应该能够重新创建 b'\xCC'
    • @m4tx:说实话,我不买票里给出的解释,我戳开发者提供更好的解释。 b'\x80' -> '\udc80' -> b'\x80' 对我来说似乎完全可以往返,除非 UTF-16 和 UTF-32 编码器遇到不适合正常 2 字节或 4 字节的代码单元的问题模式。
    【解决方案2】:

    如果你使用surrogatepass(而不是surrogateescape),那么在 Python 3 上应该可以工作。

    参见:https://docs.python.org/3/library/codecs.html#codec-base-classes(表示surrogatepass 允许对代理代码进行编码和解码(用于utf 相关编码)。

    【讨论】:

      猜你喜欢
      • 2017-04-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-03
      • 2017-09-01
      • 1970-01-01
      • 2019-05-14
      • 1970-01-01
      • 2011-04-10
      相关资源
      最近更新 更多