Question

J'ai une chaîne unicode du type "Tanim". qui est codé comme "Tan% u0131m" en quelque sorte. Comment puis-je convertir cette chaîne encodée en unicode d'origine. Apparemment, urllib.unquote ne prend pas en charge l’unicode.

Était-ce utile?

La solution

% 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 consister à encoder la chaîne en UTF-8, puis à échapper les octets obtenus avec% XX. Ce schéma est supporté par urllib.unquote:

>>> urllib2.unquote("%0a")
'\n'

Malheureusement, si vous avez vraiment besoin de prendre en charge% uXXXX, vous devrez probablement lancer votre propre décodeur. Sinon, il est probablement préférable de simplement encoder votre unicode en UTF-8 et ensuite é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'

Autres conseils

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)

Ceci le fera si vous devez absolument avoir ceci (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 s’effraie parfois lorsque la chaîne contient à la fois des caractères encodés en ascii et des caractères encodés en unicode. Je pense que c’est spécifiquement quand il y a des caractères de la plage supérieure 128 comme «\ xab» en plus de l’unicode.

par exemple. "% 5B% AB% u03E1% BB% 5D" provoque cette erreur.

J'ai découvert que si vous veniez tout d'abord de faire les unicodes, le problème disparaissait:

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 de codage non standard , rejeté par les organismes de normalisation mais toujours produit par certains encodeurs. La fonction urllib.parse.unquote () de Python ne peut pas les gérer.

Heureusement, créer votre propre décodeur n’est pas si difficile. Les entrées % uhhhh sont censées être des codes UTF-16 ici, nous devons donc prendre paires de substitution dans le compte. J'ai également vu des codes % hh combinés, pour ajouter à la confusion.

Dans cet esprit, voici un décodeur qui fonctionne à la fois en Python 2 et en 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)

Cette fonction est fortement inspirée de la .

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 les versions 2.4 - 2.7) et Python 3 (testé sur les versions 3.3 - 3.8).

scroll top