【问题标题】:Double-decoding unicode in pythonpython中的双解码unicode
【发布时间】:2011-05-15 02:23:25
【问题描述】:

我正在处理一个似乎热衷于返回我认为是双 UTF-8 编码字符串的应用程序。

我发送使用 UTF-8 编码的字符串u'XüYß',因此变为X\u00fcY\u00df(等于X\xc3\xbcY\xc3\x9f)。

服务器应该简单地回显我发送的内容,但返回以下内容:X\xc3\x83\xc2\xbcY\xc3\x83\xc2\x9f(应该是X\xc3\xbcY\xc3\x9f)。如果我使用str.decode('utf-8') 解码它就变成u'X\xc3\xbcY\xc3\x9f',它看起来像一个... unicode-string,包含使用UTF-8 编码的原始字符串。

但 Python 不会让我在不先重新编码的情况下解码 unicode 字符串 - 由于某种原因它失败了,这让我无法理解:

>>> ret = 'X\xc3\x83\xc2\xbcY\xc3\x83\xc2\x9f'.decode('utf-8')
>>> ret
u'X\xc3\xbcY\xc3\x9f'
>>> ret.decode('utf-8')
# Throws UnicodeEncodeError: 'ascii' codec can't encode ...

如何说服 Python 重新解码字符串? - 和/或是否有任何(实用的)方法来调试字符串中的实际内容,而不通过所有隐式转换 print 使用它?

(是的,我已经向服务器端的开发人员报告了这种行为。)

【问题讨论】:

    标签: python unicode utf-8


    【解决方案1】:

    ret.decode() 尝试使用系统编码隐式编码 ret - 在您的情况下为 ascii。

    如果你明确地编码 unicode 字符串,你应该没问题。有一个内置编码可以满足您的需要:

    >>> 'X\xc3\xbcY\xc3\x9f'.encode('raw_unicode_escape').decode('utf-8')
    'XüYß'
    

    真的,.encode('latin1')(或 cp1252)可以,因为这就是服务器几乎肯定会使用的。 raw_unicode_escape 编解码器最后只会给你一些可识别的东西,而不是引发异常:

    >>> '€\xe2\x82\xac'.encode('raw_unicode_escape').decode('utf8')
    '\\u20ac€'
    
    >>> '€\xe2\x82\xac'.encode('latin1').decode('utf8')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    UnicodeEncodeError: 'latin-1' codec can't encode character '\u20ac' in position 0: ordinal not in range(256)
    

    如果您遇到这种混合数据,您可以再次使用编解码器,对所有内容进行规范化:

    >>> '€\xe2\x82\xac'.encode('raw_unicode_escape').decode('utf8')
    '\\u20ac€'
    
    >>> '\\u20ac€'.encode('raw_unicode_escape')
    b'\\u20ac\\u20ac'
    >>> '\\u20ac€'.encode('raw_unicode_escape').decode('raw_unicode_escape')
    '€€'
    

    【讨论】:

    • - 不需要用我可怕的东西。
    【解决方案2】:

    您想要的是 Unicode 代码点 X 被编码为相同字节值 X 的编码。对于 0-255 内的代码点,您可以使用 latin-1 编码:

    def double_decode(bstr):
        return bstr.decode("utf-8").encode("latin-1").decode("utf-8")
    

    【讨论】:

      【解决方案3】:

      不要使用这个!使用@hop's solution

      我讨厌的 hack:(畏缩!但悄悄地。这不是我的错,是服务器开发人员的错)

      def double_decode_unicode(s, encoding='utf-8'):
          return ''.join(chr(ord(c)) for c in s.decode(encoding)).decode(encoding)
      

      那么,

      >>> double_decode_unicode('X\xc3\x83\xc2\xbcY\xc3\x83\xc2\x9f')
      u'X\xfcY\xdf'
      >>> print _
      XüYß
      

      【讨论】:

      • 好问题,顺便说一句。一个糟糕的情况。我希望其他人能想出一个比chr(ord(c)) 更简洁的解决方案来将unicode 转换为str,逐个字符...
      • f(char) for char in string 要求编码。
      • 通过某个函数将字符串中的每个字符按顺序转换,这就是编码和解码的定义,就是这样。
      • @hop:当然,但作为一种解决方案,这看起来很可怕。你的.encode('raw_unicode_escape') 更干净(除了你的解决方案的 unicode->str 步骤比我的快六倍之外)。
      【解决方案4】:

      这是一个可以帮助你的小脚本,doubledecode.py -- https://gist.github.com/1282752

      【讨论】:

        猜你喜欢
        • 2014-03-21
        • 2017-05-13
        • 2019-12-19
        • 2012-04-10
        • 1970-01-01
        • 2021-09-01
        • 2017-04-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多