2013-02-27 16 views
33

den URI zu kodieren, habe ich urllib.quote("schönefeld") aber, wenn einige nicht-ASCII-Zeichen in Zeichenfolge vorhanden ist, thorws esurllib.quote() throws KeyError

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

Meine Eingabezeichenfolgen sind köln, brønshøj, schönefeld usw.

Wenn Ich habe versucht, nur Anweisungen in Windows (mit python2.7, pyscripter IDE) zu drucken. Aber in Linux löst es Ausnahme aus (ich denke Plattform ist nicht wichtig).

Das ist, was ich versuche:

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

Explo der Ausgabe Grund: in urllib.quote(), tatsächlich return ''.join(map(quoter, s)) Ausnahme throwin werden.

Der Code in urllib ist:

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

Der Grund für die Ausnahme in ''.join(map(quoter, s)) ist, für jedes Element in s, wird quoter Funktion und schließlich die Liste aufgerufen wird, durch '' und wieder zusammengefügt werden.

Für Nicht-ASCII-Zeichen è ist der äquivalente Schlüssel %E8, der in _safe_map Variable darstellt. Aber wenn ich quote ('è') anrufe, sucht es nach dem Schlüssel \xe8. So dass der Schlüssel nicht existiert und Ausnahme ausgelöst wird.

Also, ich habe nur s = [el.upper().replace("\\X","%") for el in s] vor dem Aufruf ''.join(map(quoter, s)) innerhalb Try-außer-Block geändert. Jetzt funktioniert es gut.

Aber ich bin ärgerlich, was ich getan habe, ist richtige Vorgehensweise oder es wird jedes andere Problem erstellen? Und ich habe auch mehr als 200 Instanzen von Linux, die sehr schwierig ist, dieses Update in allen Instanzen bereitzustellen.

+2

Ist das Python 2 mit Unicode-Werten? Es funktioniert gut für bereits codierte Daten. –

+1

Sie erhalten * keinen * Fehler für 'urllib.quote ('sch \ xe9nefeld')'. Sie erhalten * nur * den Fehler für 'urllib.quote (u'sch \ xe9nefeld ')' (beachten Sie das 'u''' Unicode-Literal). –

+1

@MartijnPieters so 'cmdString =" http: // baseurl "+ Zitat (" schönefeld ")' das sollte wie sein 'cmdString = u" http: // baseurl "+ Zitat (u" schönefeld ")'? – Garfield

Antwort

54

Sie versuchen, Unicode-Daten zu zitieren, also müssen Sie entscheiden, wie Sie das in URL-sichere Bytes umwandeln.

Die Zeichenfolge zuerst in Byte codieren. UTF-8 wird häufig verwendet:

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

jedoch die Codierung hängt davon ab, was der Server akzeptieren. Es ist am besten, sich an die Codierung zu halten, mit der das ursprüngliche Formular gesendet wurde.

+0

utf-8 hat einen stärkeren Fall als Ihre Antwort impliziert. [Alle großen Browser verwenden utf-8] (http://www.w3.org/International/articles/idn-and-iri/#iriworks), bevor beim Erstellen von URIs die Codierung in Prozent erfolgt. [IRI] (http://www.ietf.org/rfc/rfc3987) zu [URI] (http://www.ietf.org/rfc/rfc3986) muss mit utf-8 konvertiert werden. Andere Kodierungen werden auf Legacy-Servern verwendet. – jfs

+0

@ J.F.Sebastian: Sicher, die Pfadelemente von URIs verwenden UTF-8. Aber das ist der Abfrageteil stattdessen. Was ein Browser für die Codierung in der Abfragezeichenfolge verwendet, ist weniger gut definiert und basierte in der Vergangenheit auf der Codierung der HTML-Seite, von der das Formular stammt. –

0

ich das als @underscore exakt die gleichen Fehler hatte gefunden werden kann, aber in meinem Fall das Problem war, dass Karte (quoter, s) versucht, nach dem Schlüssel u'\xe9' zu suchen, der nicht in der _safe_map war. Jedoch \xe9 war, so löste ich das Problem, indem ich u'\xe9' durch \xe9 in s ersetzte.

Darüber hinaus sollte nicht die return Anweisung innerhalb der try/except sein? Ich musste das auch ändern, um das Problem vollständig zu lösen.