在python中双解码unicode

时间:2010-11-24 12:56:47

标签: python unicode utf-8

我正在努力反对一个似乎热衷于返回的应用程序,我认为是双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使用它?

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

4 个答案:

答案 0 :(得分:21)

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

答案 1 :(得分:1)

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

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

答案 2 :(得分:0)

请勿使用此功能!使用@hop's solution

我讨厌的黑客:(畏缩!但是很安静。这不是我的错,这是服务器开发人员的错)

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ß

答案 3 :(得分:0)

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