Pregunta

Tengo una cadena unicode como '' Tanim '' que está codificado como " Tan% u0131m " de algun modo. ¿Cómo puedo convertir esta cadena codificada de nuevo a Unicode original? Aparentemente, urllib.unquote no es compatible con Unicode.

¿Fue útil?

Solución

% uXXXX es un esquema de codificación no estándar que ha sido rechazado por el w3c, a pesar del hecho de que una implementación continúa viviendo en JavaScript.

La técnica más común parece ser UTF-8 codificar la cadena y luego% escapar de los bytes resultantes usando% XX. Este esquema es compatible con urllib.unquote:

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

Desafortunadamente, si realmente necesita para admitir% uXXXX, probablemente tendrá que rodar su propio decodificador. De lo contrario, es probable que sea mucho más preferible simplemente codificar UTF-8 en su Unicode y luego% escapar de los bytes resultantes.

Un ejemplo más completo:

>>> u"Tanım"
u'Tan\u0131m'
>>> url = urllib.quote(u"Tanım".encode('utf8'))
>>> urllib.unquote(url).decode('utf8')
u'Tan\u0131m'

Otros consejos

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)

Esto lo hará si absolutamente tiene que tener esto (realmente estoy de acuerdo con los gritos de "no estándar"):

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

hay un error en la versión anterior donde a veces se asusta cuando hay caracteres codificados con ASCII y codificados con Unicode en la cadena. Creo que es específicamente cuando hay caracteres del rango superior de 128 como '\ xab' además de Unicode.

ej. "% 5B% AB% u03E1% BB% 5D " causa este error.

Descubrí que si primero hiciste los Unicode, el problema desapareció:

def unquote_u(source):
  result = source
  if '%u' in result:
    result = result.replace('%u','\\u').decode('unicode_escape')
  result = unquote(result)
  return result

Tiene una URL que utiliza un esquema de codificación no estándar , rechazado por los organismos de normalización pero aún siendo producido por algunos codificadores. La función Python urllib.parse.unquote () no puede manejarlos.

Crear su propio decodificador no es tan difícil, afortunadamente. Las entradas % uhhhh están destinadas a ser UTF-16 puntos de código aquí, por lo que debemos tomar pares sustitutos en cuenta. También he visto % hh puntos de código mezclados, para mayor confusión.

Con eso en mente, aquí hay un decodificador que funciona tanto en Python 2 como en Python 3, siempre que pase un objeto str en Python 3 (Python 2 se preocupa menos):

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 función está fuertemente inspirada en

scroll top