web-dev-qa-db-fra.com

Existe-t-il un substitut prêt pour unicode que je peux utiliser pour urllib.quote et urllib.unquote dans Python 2.6.5?

urllib.quote Et urllib.unquote De Python ne gèrent pas correctement Unicode dans Python 2.6.5. Voici ce qui se passe:

In [5]: print urllib.unquote(urllib.quote(u'Cataño'))
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)

/home/kkinder/<ipython console> in <module>()

/usr/lib/python2.6/urllib.pyc in quote(s, safe)
   1222             safe_map[c] = (c in safe) and c or ('%%%02X' % i)
   1223         _safemaps[cachekey] = safe_map
-> 1224     res = map(safe_map.__getitem__, s)
   1225     return ''.join(res)
   1226 

KeyError: u'\xc3'

L'encodage de la valeur en UTF8 ne fonctionne pas non plus:

In [6]: print urllib.unquote(urllib.quote(u'Cataño'.encode('utf8')))
Cataño

C'est reconnu comme un bogue et il y a un correctif , mais pas pour ma version de Python.

Ce que je voudrais, c'est quelque chose de similaire à urllib.quote/urllib.unquote, mais gère correctement les variables Unicode, de sorte que ce code fonctionne:

decode_url(encode_url(u'Cataño')) == u'Cataño'

Des recommandations?

41
Ken Kinder

Urllib.quote et urllib.unquote de Python ne gèrent pas correctement Unicode

urllib ne gère pas du tout Unicode. Les URL ne contiennent pas de caractères non ASCII, par définition. Lorsque vous avez affaire à urllib, vous ne devez utiliser que des chaînes d'octets. Si vous voulez que ceux-ci représentent des caractères Unicode, vous devrez les encoder et les décoder manuellement.

IRIs peut contenir des caractères non-ASCII, les encodant comme des séquences UTF-8, mais Python n'a pas, à ce stade, un irilib .

L'encodage de la valeur en UTF8 ne fonctionne pas non plus:

In [6]: print urllib.unquote(urllib.quote(u'Cataño'.encode('utf8')))
Cataño

Ah, bien maintenant vous tapez Unicode dans une console, et faites print- Unicode sur la console. Ceci n'est généralement pas fiable, en particulier sous Windows et dans votre cas avec la console IPython .

Tapez-le le long du chemin avec des séquences de barres obliques inverses et vous pouvez plus facilement voir que le bit urllib fonctionne réellement:

>>> u'Cata\u00F1o'.encode('utf-8')
'Cata\xC3\xB1o'
>>> urllib.quote(_)
'Cata%C3%B1o'

>>> urllib.unquote(_)
'Cata\xC3\xB1o'
>>> _.decode('utf-8')
u'Cata\xF1o'
43
bobince

"" "L'encodage de la valeur en UTF8 ne fonctionne pas non plus" "" ... le résultat de votre code est un objet str qui, à une supposition, semble être l'entrée encodée en UTF-8. Vous devez le décoder ou définir "ne fonctionne pas" - que faire vous attendez?

Remarque: pour ne pas avoir à deviner l'encodage de votre terminal et le type de vos données, utilisez print repr(whatever) au lieu de print whatever.

>>> # Python 2.6.6
... from urllib import quote, unquote
>>> s = u"Cata\xf1o"
>>> q = quote(s.encode('utf8'))
>>> u = unquote(q).decode('utf8')
>>> for x in (s, q, u):
...     print repr(x)
...
u'Cata\xf1o'
'Cata%C3%B1o'
u'Cata\xf1o'
>>>

En comparaison:

>>> # Python 3.2
... from urllib.parse import quote, unquote
>>> s = "Cata\xf1o"
>>> q = quote(s)
>>> u = unquote(q)
>>> for x in (s, q, u):
...     print(ascii(x))
...
'Cata\xf1o'
'Cata%C3%B1o'
'Cata\xf1o'
>>>
5
John Machin

J'ai donc eu le même problème: je voulais mettre des paramètres de requête dans une url, mais certains d'entre eux contenaient des caractères étranges (diacritiques).

La gestion de l'encodage a donné une URL désordonnée et était fragile.

Ma solution était de remplacer chaque accent/caractère unicode étrange par son équivalent ascii. C'est simple grâce à unidecode: Quelle est la meilleure façon de supprimer les accents dans une Python chaîne unicode?

pip install unidecode

puis

from unidecode import unidecode
print unidecode(u"éèê") 
# prints eee

donc j'ai une URL propre. Fonctionne également pour le chinois, etc.

1
Ehvince

J'ai rencontré le même problème et utilisé une fonction d'assistance pour gérer les fonctions non-ascii et urllib.urlencode (qui comprend quote et unquote):

def utf8_urlencode(params):
    import urllib as u
    # problem: u.urlencode(params.items()) is not unicode-safe. Must encode all params strings as utf8 first.
    # UTF-8 encodes all the keys and values in params dictionary
    for k,v in params.items():
        # TRY urllib.unquote_plus(artist.encode('utf-8')).decode('utf-8')
        if type(v) in (int, long, float):
            params[k] = v
        else:
            try:
                params[k.encode('utf-8')] = v.encode('utf-8')
            except Exception as e:
                logging.warning( '**ERROR utf8_urlencode ERROR** %s' % e )
    return u.urlencode(params.items()).decode('utf-8')

adopté de encodage/décodage d'URL Unicode avec Python

1
Marc Maxmeister