web-dev-qa-db-ja.com

urllib.quote()throws KeyError

URIをエンコードするには、urllib.quote("schönefeld")を使用しましたが、文字列に非ASCII文字が存在する場合は、

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

私の入力文字列は_köln, brønshøj, schönefeld_などです。

Windowsでステートメントを印刷しようとしたとき(python2.7、pyscripter IDEを使用)。しかし、Linuxでは例外が発生します(プラットフォームは関係ないと思います)。

これは私が試していることです:

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

問題の理由の調査:urllib.quote()で、実際にはreturn ''.join(map(quoter, s))でスローされている例外。

Urllibのコードは次のとおりです。

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

例外の理由は''.join(map(quoter, s))にあり、sのすべての要素に対して、quoter関数が呼び出され、最後にリストが ''で結合されて返されます。

非ASCII文字_è_の場合、同等のキーは_%E8_になり、__safe_map_変数に表示されます。しかし、quote( 'è')を呼び出すと、キー_\xe8_が検索されます。そのため、キーは存在せず、例外がスローされます。

そのため、try-exceptブロック内でs = [el.upper().replace("\\X","%") for el in s]を呼び出す前に''.join(map(quoter, s))を変更しました。今では正常に動作します。

しかし、私がやったことは正しいアプローチであるか、それが他の問題を引き起こすでしょうか?また、Linuxの200以上のインスタンスがあり、すべてのインスタンスにこの修正プログラムを展開するのは非常に困難です。

38
Garfield

Unicodeデータを引用しようとしているので、それをURLセーフバイトに変換する方法を決定する必要があります。

最初に文字列をバイトにエンコードします。 UTF-8がよく使用されます:

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

ただし、エンコーディングサーバーが受け入れるものによって異なります。元のフォームが送信されたエンコーディングに固執することをお勧めします。

59
Martijn Pieters

文字列をユニコードに変換するだけで問題を解決しました。

ここにスニペットがあります:

try:
    unicode(mystring, "ascii")
except UnicodeError:
    mystring = unicode(mystring, "utf-8")
else:
    pass

ソリューションの詳細な説明は、 http://effbot.org/pyfaq/what-does-unicodeerror-ascii-decoding-encoding-error-ordinal-not-in-range-128で見つけることができます-mean.htm

2
Garfield

@underscoreとまったく同じエラーがありましたが、私の場合、問題はmap(quoter、s)がu'\xe9'にないキー_safe_mapを検索しようとしたことです。ただし、\xe9はそうだったので、su'\xe9'\xe9に置き換えることで問題を解決しました。

さらに、returnステートメントはtry/except内にあるべきではありませんか?また、問題を完全に解決するためにこれを変更する必要がありました。

1
Sebastien