我正在努力反对一个似乎热衷于返回的应用程序,我认为是双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
使用它?
(是的,我已经向服务器端的开发人员报告了这种行为。)
答案 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