У вас есть URL с использованием нестандартной схемы кодирования , отклоненной органами стандартизации, но все еще производимой некоторыми кодировщиками. Функция Python urllib.parse.unquote()
не может справиться с этим.
К счастью, создание собственного декодера не так сложно. Здесь %uhhhh
записей означают UTF-16 кодовые точки, поэтому мы должны учитывать суррогатных пар . Я также видел смешанные %hh
кодовые точки для дополнительной путаницы.
Имея это в виду, вот декодер, который работает как в Python 2, так и в Python 3, при условии, что вы передаете объект str
в Python 3 (Python 2 не заботится):
try:
# Python 3
from urllib.parse import unquote
unichr = chr
except ImportError:
# Python 2
from urllib import unquote
def unquote_unicode(string, _cache={}):
string = unquote(string) # handle two-digit %hh components first
parts = string.split(u'%u')
if len(parts) == 1:
return parts
r = [parts[0]]
append = r.append
for part in parts[1:]:
try:
digits = part[:4].lower()
if len(digits) < 4:
raise ValueError
ch = _cache.get(digits)
if ch is None:
ch = _cache[digits] = unichr(int(digits, 16))
if (
not r[-1] and
u'\uDC00' <= ch <= u'\uDFFF' and
u'\uD800' <= r[-2] <= u'\uDBFF'
):
# UTF-16 surrogate pair, replace with single non-BMP codepoint
r[-2] = (r[-2] + ch).encode(
'utf-16', 'surrogatepass').decode('utf-16')
else:
append(ch)
append(part[4:])
except ValueError:
append(u'%u')
append(part)
return u''.join(r)
Функция в значительной степени вдохновлена текущей реализацией стандартной библиотеки .
Демо-версия:
>>> print(unquote_unicode('Tan%u0131m'))
Tanım
>>> print(unquote_unicode('%u05D0%u05D9%u05DA%20%u05DE%u05DE%u05D9%u05E8%u05D9%u05DD%20%u05D0%u05EA%20%u05D4%u05D8%u05E7%u05E1%u05D8%20%u05D4%u05D6%u05D4'))
איך ממירים את הטקסט הזה
>>> print(unquote_unicode('%ud83c%udfd6')) # surrogate pair
?
>>> print(unquote_unicode('%ufoobar%u666')) # incomplete
%ufoobar%u666
Функция работает на Python 2 (проверено на 2.4 - 2.7) и Python 3 (проверено на 3.3 - 3.8).