2013-02-27 22 views
33

atar ben urllib.quote("schönefeld") kullanılan ancak bazı ASCII olmayan karakterler dizesi var, bunun My giriş dizeleriurllib.quote(), URI kodlamak için KeyError

KeyError: u'\xe9' 
Code: return ''.join(map(quoter, s)) 

thorws vb köln, brønshøj, schönefeld

zaman Pencerelerde yalnızca baskı ifadelerini denedim (python2.7, pyscripter IDE kullanarak). Ancak linux'da istisna kaldırıyor (sanırım platform önemli değil).

Bu benim çalışıyorum budur:

from commands import getstatusoutput 
queryParams = "schönefeld"; 
cmdString = "http://baseurl" + quote(queryParams) 
print getstatusoutput(cmdString) 

sorunu nedeni keşfetmek: urllib.quote() yılında, aslında istisna return ''.join(map(quoter, s)) de throwin ediliyor. urllib içinde

kodudur: istisna için

def quote(s, safe='/'): 
    if not s: 
     if s is None: 
      raise TypeError('None object cannot be quoted') 
     return s 
    cachekey = (safe, always_safe) 
    try: 
     (quoter, safe) = _safe_quoters[cachekey] 
    except KeyError: 
     safe_map = _safe_map.copy() 
     safe_map.update([(c, c) for c in safe]) 
     quoter = safe_map.__getitem__ 
     safe = always_safe + safe 
     _safe_quoters[cachekey] = (quoter, safe) 
     if not s.rstrip(safe): 
     return s 
     return ''.join(map(quoter, s)) 

nedeni, ''.join(map(quoter, s)) olduğu s her eleman için, teklif sahibi işlevi çağrılır ve son olarak liste 'de katılacak ve geri döndü.

Ascii char için è, eşdeğer anahtar _safe_map değişkeninde bulunan %E8 olacaktır. Ama ben alıntı ('è') çağırdığımda, \xe8 anahtarını arar. Böylece anahtar mevcut değil ve istisna atıldı.

Yani, try-except bloğu içinde ''.join(map(quoter, s))'u aramadan önce s = [el.upper().replace("\\X","%") for el in s]'u değiştirdim. Şimdi iyi çalışıyor.

Ama ne yaptığımı can sıkıcı bir yaklaşım mıyım yoksa başka bir sorun yaratacaktır? Ayrıca, bu düzeltmeyi tüm durumlarda dağıtmak çok zor olan 200'den fazla linux örneğim var.

+2

Bu Python 2 unicode değerleri ile mi? Zaten kodlanmış veriler için iyi çalışıyor. –

+1

Yapmanız gereken bir şey değil, * urllib.quote ('sch \ xe9nefeld') '. * Sadece * urllib.quote (u'sch \ xe9nefeld ') '(' u '' unicode literal) not alın. –

+1

@MartijnPieters bu yüzden cmdString = "http: // baseurl" + quote ("schönefeld") 'bu cmdString = u" http: // baseurl "+ quote (u" schönefeld ")' gibi olmalıdır? – Garfield

cevap

54

Unicode verilerini alıntılamaya çalışıyorsunuz, bu nedenle URL güvenli baytlara nasıl dönüştüreceğinize karar vermeniz gerekiyor.

Dizeyi önce bayt olarak kodlayın. UTF-8 sıklıkla kullanılır:

>>> import urllib 
>>> urllib.quote(u'sch\xe9nefeld') 
/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib.py:1268: UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal 
    return ''.join(map(quoter, s)) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib.py", line 1268, in quote 
    return ''.join(map(quoter, s)) 
KeyError: u'\xe9' 
>>> urllib.quote(u'sch\xe9nefeld'.encode('utf8')) 
'sch%C3%A9nefeld' 

Ancak kodlama sunucu kabul eder bağlıdır. Orijinal formun gönderildiği kodlamaya uymak en iyisidir.

+0

utf-8, cevabınızın ima ettiğinden daha güçlü bir duruma sahiptir. [Tüm büyük tarayıcılar URI'leri oluştururken yüzde-kodlamadan önce utf-8] (http://www.w3.org/International/articles/idn-and-iri/#iriworks) kullanırlar. [IRI] (http://www.ietf.org/rfc/rfc3987) [URI] (http://www.ietf.org/rfc/rfc3986) utf-8 kullanılarak dönüştürülmelidir. Diğer kodlamalar eski sunucularda kullanılır. – jfs

+0

@ J.F.Sebastian: Elbette, URI'lerin yol öğeleri UTF-8'i kullanır. Ancak bunun yerine sorgu kısmı budur. Sorgu dizesinde kodlama için kullanılan bir tarayıcı daha az iyi tanımlanmıştır ve geçmişte, formun kaynaklandığı HTML sayfasının kodlamasına dayanmaktadır. –

0

bulunabilir

try: 
    unicode(mystring, "ascii") 
except UnicodeError: 
    mystring = unicode(mystring, "utf-8") 
else: 
    pass 
, s) _safe_map'da bulunmayan u'\xe9' anahtarını aramaya çalıştı. Ancak, \xe9 oldu, bu yüzden sorunu'u \xe9 değiştirerek s içinde çözdüm.

Ayrıca, return ifadesi try/except içinde bulunmamalıdır? Ayrıca sorunu tamamen çözmek için bunu değiştirmek zorunda kaldım.