Hoe unquote een urlencoded unicode-tekenreeks in de python?

Ik heb een unicode-tekenreeks als “Tanım” die is gecodeerd als “Tan%u0131m een of andere manier”. Hoe kan ik dit omzetten gecodeerde tekenreeks terug naar de oorspronkelijke unicode.
Blijkbaar urllib.unquote unicode niet ondersteunt.

InformationsquelleAutor hamdiakoguz | 2008-11-18



5 Replies
  1. 68

    %uXXXX is een een niet-standaard codering regeling dat is afgewezen door de w3c, ondanks het feit dat een implementatie blijft voortleven in JavaScript land.

    De meer gangbare techniek lijkt te worden naar UTF-8 coderen van de string en dan % ontsnappen aan de resulterende bytes, %XX. Deze regeling wordt ondersteund door urllib.unquote:

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

    Helaas, als je echt moet te ondersteunen %uXXXX, zult u waarschijnlijk uw eigen roll-decoder. Anders is het waarschijnlijk veel beter om gewoon UTF-8-codering van uw unicode en dan % ontsnappen aan de resulterende bytes.

    Een volledig voorbeeld:

    >>> u"Tanım"
    u'Tan\u0131m'
    >>> url = urllib.quote(u"Tanım".encode('utf8'))
    >>> urllib.unquote(url).decode('utf8')
    u'Tan\u0131m'
    • ‘urllib2.unquote’ moet ‘urllib.unquote’
    • Interessant dat een URI is een procent gecodeerd byte-string in plaats van een teken-string.
    • niet necessarly, in Python 2.7.5+ kunt u gebruik maken van urllib2.unquote gewoon proberen print(dir(urllib2))
    • urllib.unquote(url.coderen(‘utf-8’)) werkte voor mij in de plaats
    • is het een slechte gewoonte om iets te doen als unquote(urlencode())?
  2. 10
    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)
    • Dit werkt alleen voor Python 2, helaas, die is snel nadert haar einde-van-leven. Het is niet moeilijk om te corrigeren voor om deze Python 2 en 3 compatibel (try: unichr, except NameError: unichr = chr), maar deze versie niet omgaan met vervangende paren. De bedoeling van de %hhhh ontsnappen formaat te coderen UTF-16 codepoints, dus voor niet-BMP-sequenties (zoals een groot aantal van emoji) je zou krijgen van een ongeldige tekenreeks op alles wat maar een UCS-2 Python 2 bouwen.
  3. 6

    Zal dit doen als u absoluut moet hebben dit (ik ben het eens met de kreten van “niet-standaard”):

    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
    • Een iets pathologisch geval, maar: unquote_u(‘Tan%25u0131m’) –> u ‘Tan\u0131m’ in plaats van ‘Tan%u0131’ als het moet. Slechts een herinnering aan waarom wil je waarschijnlijk niet tot het schrijven van een decoder, tenzij je het echt nodig hebt.
    • Ik ben het volledig eens. Dat is de reden waarom ik echt niet happig was om een werkelijke oplossing. Deze dingen zijn nooit zo eenvoudig. De O. P. zou zijn wanhopige al, en ik denk dat dit een uitstekende aanvulling op uw antwoord.
    • Dit werkt alleen voor Python 2, helaas, die is snel nadert haar einde-van-leven. Het gebruik van unicode_escape maakt het een beetje moeilijker om te corrigeren voor Python 3 gebruiken (je zou nodig hebben om te coderen naar utf-8), maar deze versie niet omgaan met vervangende paren. De bedoeling van de %hhhh ontsnappen formaat te coderen UTF-16 codepoints, dus voor niet-BMP-sequenties (zoals een groot aantal van emoji) je zou krijgen van een ongeldige tekenreeks op alles wat maar een UCS-2 Python 2 bouwen.
  4. 4

    er is een bug in de bovenstaande versie waar freaks soms als er zowel ascii gecodeerd en gecodeerd in unicode-tekens in de string. Ik denk dat het met name wanneer er tekens van de bovenste 128 bereik zoals ‘\xab’ in aanvulling op unicode.

    bijv. “%5B%AB%u03E1%BB%5D” de oorzaak van deze fout.

    Ik vond als je net deed de unicode-ones eerste, het probleem weg ging:

    def unquote_u(source):
      result = source
      if '%u' in result:
        result = result.replace('%u','\\u').decode('unicode_escape')
      result = unquote(result)
      return result
    • \xab is geen personage, maar een byte. In uw voorbeeld “string” bevat zowel bytes en karakters, die is niet geldig als één tekenreeks in een taal die ik ken.
    • Wat zou "%5B%AB%u03E1%BB%5D" decoderen zo? 0x5B 0xAB en 0xBB 0x5D zijn nauwelijks geldig UTF-8 reeksen.
    • Ik heb gezien dat real-life cases (een Java-bibliotheek ergens) dat codeert voor sommige ASCII codepoints zoals spaties om %hh sequenties, en iets meer dan 0x7F te %uhhhh sequenties. Verschrikkelijk, maar parsable.
  5. 1

    Heb je een URL met behulp van een een niet-standaard codering regeling, afgewezen door de normalisatie-instellingen, maar nog steeds wordt geproduceerd door sommige encoders. De Python urllib.parse.unquote() functie kan niet omgaan met deze.

    Het maken van uw eigen decoder is niet zo moeilijk, gelukkig. %uhhhh vermeldingen zijn bedoeld om te worden UTF-16 codepoints hier, dus we moeten vervangende paren rekening. Ik heb ook gezien %hh codepoints gemengd, voor extra verwarring.

    Met dat in gedachten, hier is een decoder die werkt in beide Python 2 en Python 3, op voorwaarde dat u pas in een str object in Python 3 (Python 2 geeft minder):

    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)

    De functie is sterk geïnspireerd door de de huidige standaard-bibliotheek uitvoering.

    Demo:

    >>> 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

    De functie werkt op Python 2 (getest op 2.4 – 2.7) en Python 3 (getest op 3.3 – 3.8).

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *