文字列オブジェクトを比較するリスト内包表記を使用しようとしていますが、文字列の1つはjson.loadsの副産物であるutf-8です。シナリオ:
us = u'MyString' # is the utf-8 string
私の質問の第1部、なぜこれがFalseを返すのですか? :
us.encode('utf-8') == "MyString" ## False
パート2-リスト内包内でどのように比較できますか?
myComp = [utfString for utfString in jsonLoadsObj
if utfString.encode('utf-8') == "MyString"] #wrapped to read on S.O.
編集:Python 2.7を使用するGoogle App Engineを使用しています
問題のより完全な例を次に示します。
#json coming from remote server:
#response object looks like: {"number1":"first", "number2":"second"}
data = json.loads(response)
k = data.keys()
I need something like:
myList = [item for item in k if item=="number1"]
#### I thought this would work:
myList = [item for item in k if item.encode('utf-8')=="number1"]
間違ったデータセットをループしている必要があります。 JSONロードされた辞書を直接ループするだけで、最初に.keys()
を呼び出す必要はありません。
data = json.loads(response)
myList = [item for item in data if item == "number1"]
u"number1"
を使用して、Unicodeとバイト文字列間の暗黙的な変換を回避することができます。
data = json.loads(response)
myList = [item for item in data if item == u"number1"]
両方のバージョンは正常に動作します:
>>> import json
>>> data = json.loads('{"number1":"first", "number2":"second"}')
>>> [item for item in data if item == "number1"]
[u'number1']
>>> [item for item in data if item == u"number1"]
[u'number1']
最初の例では、us
はnotUTF-8文字列であることに注意してください。ユニコードデータであるため、json
ライブラリは既にそれをデコードしています。一方、UTF-8文字列は、シーケンスエンコードされたバイトです。 UnicodeとPythonを読んで違いを理解してください。
すべてのソフトウェア開発者がユニコードと文字セットについて絶対的かつ積極的に知っておくべき絶対的な最小値(言い訳はありません!) by Joel Spolsky
Pragmatic Unicode by Ned Batchelder
Python 2、テストがTrue
を返すというあなたの期待は正しいでしょう、あなたは何か間違ったことをしています:
>>> us = u'MyString'
>>> us
u'MyString'
>>> type(us)
<type 'unicode'>
>>> us.encode('utf8') == 'MyString'
True
>>> type(us.encode('utf8'))
<type 'str'>
比較のために文字列をUTF-8にエンコードする必要があるnoがあります。代わりにUnicodeリテラルを使用します。
myComp = [elem for elem in json_data if elem == u"MyString"]
バイト文字列(_'MyString'
_)とUnicodeコードポイントの文字列(_u'MyString'
_)を比較しようとしています。これは「リンゴとオレンジ」の比較です。残念ながら、Python 2は、常にFalse
を返すのではなく、この比較が有効であると見せかけます:
_>>> u'MyString' == 'MyString' # in my opinion should be False
True
_
正しい比較がどうあるべきかを決めるのは、設計者/開発者としてのあなた次第です。考えられる1つの方法を次に示します。
_a = u'MyString'
b = 'MyString'
a.encode('UTF-8') == b # True
_
a == b.decode('UTF-8')
の代わりに上記をお勧めします。すべての_u''
_スタイルの文字列は、いくつかの奇妙な場合を除き、UTF-8でバイトにエンコードできますが、すべてのバイト文字列をUnicodeにデコードできるわけではありませんそのように。
しかし、比較する前にUnicode文字列のUTF-8エンコードを行うことを選択した場合、Windowsシステムでのu'Em dashes\u2014are cool'.encode('UTF-8') == 'Em dashes\x97are cool'
の場合、これは失敗します。ただし、.encode('Windows-1252')
を代わりに使用すると、成功します。それが、リンゴとオレンジの比較だからです。