Вы должны использовать urllib.unquote
, а не ручную замену:
>>> import urllib
>>> raw = '%C3%BE%C3%A6%C3%B0%C3%B6'
>>> urllib.unquote(raw)
'\xc3\xbe\xc3\xa6\xc3\xb0\xc3\xb6'
>>> unicode(urllib.unquote(raw), 'utf-8')
u'\xfe\xe6\xf0\xf6'
Основная проблема здесь заключается в том, что у вас есть фундаментальное неправильное понимание того, что такое шестнадцатеричные побеги.repr
непечатаемого символа может быть выражен как шестнадцатеричный escape, который выглядит как одиночная обратная косая черта, за которой следует «x», за которым следуют два шестнадцатеричных символа.Это также, как вы могли бы ввести эти символы в строковый литерал, но это все еще только один символ.Ваша строка replace
не превращает вашу исходную строку в шестнадцатеричные экранированные символы, она просто заменяет каждый «%» буквальным символом обратной косой черты, за которым следует «x».
Рассмотрим следующие примеры:
>>> len('\xC3') # this is a hex escape, only one character
1
>>> len(r'\xC3') # this is four characters, '\', 'x', 'C', '3'
4
>>> r'\xC3' == '\\xC3' # raw strings escape backslashes
True
Если по какой-то причине вы не можете использовать urllib.unquote
, должно работать следующее:
raw_uni = re.sub('%(\w{2})', lambda m: chr(int(m.group(1), 16)), raw)