【问题标题】:Why can u'\xe5' be decoded but not '\xe5'?为什么可以解码 u'\xe5' 而不能解码 '\xe5'?
【发布时间】:2017-09-20 10:23:58
【问题描述】:

这令人震惊和令人沮丧,请帮忙。

>>> a1 = '\xe5'   # type <str>
>>> a2 = u'\xe5'  # type <unicode>
>>> ord(a1)
229
>>> ord(a2)
229
>>> print a2.encode('utf-8')
å
>>> print a1.encode('utf-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 0: ordinal not in range(128)

如果a1和a2的值相同,为什么不能都编码?

我必须使用在a1 表单上返回 unicode 数据的外部 API,这使它毫无用处。 Python 显然坚持 &lt;str&gt; 类型化的字符串必须只包含 ASCII 字符,否则它拒绝对它们进行编码。它完全破坏了我的应用程序。

【问题讨论】:

  • 您是否尝试使用编码的字符集对其进行解码?
  • 嗯...原来数据被编码为 latin-1。我无法根据我能找到的任何技术细节来合理化正确的猜测。我不知道 Python 或终端或其他什么决定使用 latin-1。我只是做了一个幸运的猜测。
  • 它没有。它是由生成它的任何东西以这种方式编码的。

标签: python unicode-literals


【解决方案1】:

Ignacio 建议从实际编码中解码字节字符串(不是 ascii,而是什么?)让我尝试使用 latin-1,即使我认为它应该是 utf-8。成功了!

我从 Python2.7 curses 模块获取数据。我最好的猜测是问题出在某个地方。终端的编码是utf-8,但是现在可以了。

【讨论】:

    【解决方案2】:

    让我把你的困惑撕碎。我们先从strunicode 的区别说起。在 Python 2.X 中:

    1. str 是一个 8 位字符(1 字节)的字符串,尽可能打印为 ASCII。 str 实际上是一个字节序列,相当于 Python 3.X 中的 bytes。 *str 没有编码。
    2. unicode 是一串 Unicode 代码点。

    二、编码方式根据Python documentation

    “将 Unicode 字符串翻译成字节序列的规则称为编码。”

    然后,问自己这个问题:编码已经是字节序列的str 有意义吗?答案是不。因为str 已经是一个字节序列。但是编码unicode 确实有意义,为什么?因为它是一串 Unicode 字符代码点(即 U+00E4')。

    【讨论】:

      【解决方案3】:

      python2 中,字符串是ASCII,而在python3 中,字符串是Unicode。

      ASCII 字符的值只能在 0 到 127 之间。 然而,Unicode 字符可能具有更高的值。

      python2:

      >>> a = '\x7f'
      >>> a.encode('utf-8')
      '\x7f'
      >>> a = '\x80'
      >>> a.encode('utf-8')
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
      UnicodeDecodeError: 'ascii' codec can't decode byte 0x80 in position 0: ordinal not in range(128)
      

      python3:

      >>> a = '\x7f'
      >>> a.encode('utf-8')
      b'\x7f'
      >>> a = '\x80'
      >>> a.encode('utf-8')
      b'\xc2\x80'
      

      这在带有u 前缀的python2 中起作用的原因是因为您明确声明“这是一个 Unicode 字符串”。


      可能值得阅读以更深入地了解在python2 中使用 Unicode:


      要使用(损坏的)API,最好将返回的字符串转换为字节数组,但请注意,这在python3 中不起作用。

      >>> a = '\xe5'
      >>> b = bytearray(a)
      >>> b[0]
      229
      

      请记住,\xe5 不是有效的 Unicode (UTF-8) 字符...要将值 0xE5 存储在 UTF-8 编码字符串中,您需要存储两个字节:0xC3 0xA5 .

      【讨论】:

        【解决方案4】:

        您只能对 Unicode 字符串进行编码。如果您在字节串上调用 encode,Python 会首先尝试 decode 它,使用默认编码 - 因此会出现错误。 (请注意,这种令人困惑的行为仅在 Python 2 中出现,在 Python 3 中已被删除)。

        【讨论】:

        • 没有办法设置字节串的编码吗?数据来自运行 LANG=en_US.utf8 的终端。
        • 更好的是:有没有办法在不运行任何转换的情况下将字节字符串转换为 unicode 类型?毕竟,数组是字节精确的副本。
        猜你喜欢
        • 2019-02-05
        • 2023-03-16
        • 1970-01-01
        • 2019-12-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多