J'ai une chaîne unicode comme "Tanım" qui est codée en quelque sorte "Tan% u0131m". Comment puis-je reconvertir cette chaîne encodée en unicode d'origine. Apparemment, urllib.unquote ne prend pas en charge l'unicode.
% uXXXX est un schéma de codage non standard qui a été rejeté par le w3c, malgré le fait qu'une implémentation continue de vivre en JavaScript.
La technique la plus courante semble être de coder en UTF-8 la chaîne puis de% échapper les octets résultants en utilisant% XX. Ce schéma est pris en charge par urllib.unquote:
>>> urllib2.unquote("%0a")
'\n'
Malheureusement, si vous avez vraiment besoin de prendre en charge% uXXXX, vous devrez probablement faire rouler votre propre décodeur. Sinon, il est probablement beaucoup plus préférable de simplement coder en UTF-8 votre unicode, puis d'échapper% des octets résultants.
Un exemple plus complet:
>>> u"Tanım"
u'Tan\u0131m'
>>> url = urllib.quote(u"Tanım".encode('utf8'))
>>> urllib.unquote(url).decode('utf8')
u'Tan\u0131m'
def unquote(text):
def unicode_unquoter(match):
return unichr(int(match.group(1),16))
return re.sub(r'%u([0-9a-fA-F]{4})',unicode_unquoter,text)
Cela le fera si vous devez absolument avoir cela (je suis vraiment d'accord avec les cris de "non standard"):
from urllib import unquote
def unquote_u(source):
result = unquote(source)
if '%u' in result:
result = result.replace('%u','\\u').decode('unicode_escape')
return result
print unquote_u('Tan%u0131m')
> Tanım
il y a un bogue dans la version ci-dessus où il flippe parfois quand il y a à la fois des caractères encodés ascii et unicode dans la chaîne. Je pense que c'est spécifiquement quand il y a des caractères de la gamme 128 supérieure comme '\ xab' en plus de l'unicode.
par exemple. "% 5B% AB% u03E1% BB% 5D" provoque cette erreur.
J'ai trouvé que si vous venez de faire les unicodes en premier, le problème a disparu:
def unquote_u(source):
result = source
if '%u' in result:
result = result.replace('%u','\\u').decode('unicode_escape')
result = unquote(result)
return result
Vous avez une URL utilisant un schéma d'encodage non standard , rejeté par les organismes de normalisation mais toujours produit par certains encodeurs. La fonction Python urllib.parse.unquote()
ne peut pas les gérer.
La création de votre propre décodeur n'est pas si difficile, heureusement. %uhhhh
les entrées sont censées être les points de code UTF-16 ici, nous devons donc prendre en compte paires de substitution . J'ai aussi vu %hh
codepoints mélangés, pour plus de confusion.
Dans cet esprit, voici un décodeur qui fonctionne à la fois Python 2 et Python 3, à condition de passer un objet str
dans Python 3 (Python 2 se soucie moins):
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)
La fonction est fortement inspirée par la implémentation actuelle de la bibliothèque standard .
Démo:
>>> 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
La fonction fonctionne sur Python 2 (testé sur 2.4 - 2.7) et Python 3 (testé sur 3.3 - 3.8)).