J'essaie d'utiliser une compréhension de liste qui compare les objets chaîne, mais l'une des chaînes est utf-8, le sous-produit de json.loads. Scénario:
us = u'MyString' # is the utf-8 string
La première partie de ma question est la suivante: pourquoi cela renvoie-t-il faux? :
us.encode('utf-8') == "MyString" ## False
Deuxième partie - comment comparer dans une liste de compréhension?
myComp = [utfString for utfString in jsonLoadsObj
if utfString.encode('utf-8') == "MyString"] #wrapped to read on S.O.
EDIT: j'utilise Google App Engine, qui utilise Python 2.7
Voici un exemple plus complet du problème:
#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"]
Vous devez parcourir le mauvais ensemble de données; bouclez directement sur le dictionnaire chargé JSON, il n'est pas nécessaire d'appeler .keys()
d'abord:
data = json.loads(response)
myList = [item for item in data if item == "number1"]
Vous voudrez peut-être utiliser u"number1"
pour éviter les conversions implicites entre Unicode et les chaînes d'octets:
data = json.loads(response)
myList = [item for item in data if item == u"number1"]
Les deux versions fonctionnent bien :
>>> 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']
Notez que dans votre premier exemple, us
n'est pas une chaîne UTF-8; ce sont des données unicode, la bibliothèque json
les a déjà décodées pour vous. Une chaîne UTF-8, d'autre part, est une séquence octets codés. Vous voudrez peut-être lire sur Unicode et Python pour comprendre la différence:
nicode pragmatique par Ned Batchelder
Sur Python 2, votre attente que votre test renvoie True
serait correcte, vous faites autre chose de mal:
>>> us = u'MyString'
>>> us
u'MyString'
>>> type(us)
<type 'unicode'>
>>> us.encode('utf8') == 'MyString'
True
>>> type(us.encode('utf8'))
<type 'str'>
Il n'y a pas besoin de coder les chaînes en UTF-8 pour faire des comparaisons; utilisez plutôt des littéraux unicode:
myComp = [elem for elem in json_data if elem == u"MyString"]
Vous essayez de comparer une chaîne d'octets ('MyString'
) Avec une chaîne de points de code Unicode (u'MyString'
). Il s'agit d'une comparaison "pommes et oranges". Malheureusement, Python 2 prétend dans certains cas que cette comparaison est valide, au lieu de toujours renvoyer False
:
>>> u'MyString' == 'MyString' # in my opinion should be False
True
C'est à vous, en tant que concepteur/développeur, de décider quelle doit être la bonne comparaison. Voici une façon possible:
a = u'MyString'
b = 'MyString'
a.encode('UTF-8') == b # True
Je recommande ce qui précède au lieu de a == b.decode('UTF-8')
car toutes les chaînes de style u''
Peuvent être encodées en octets avec UTF-8, sauf peut-être dans certains cas bizarres, mais toutes les chaînes d'octets ne peuvent pas être décodées en Unicode de cette façon.
Mais si vous choisissez de faire un encodage UTF-8 des chaînes Unicode avant de comparer, cela échouera pour quelque chose comme ça sur un système Windows: u'Em dashes\u2014are cool'.encode('UTF-8') == 'Em dashes\x97are cool'
. Mais si vous .encode('Windows-1252')
à la place, cela réussirait. C'est pourquoi c'est une comparaison de pommes et d'oranges.
Je suppose que vous utilisez Python 3. us.encode('utf-8') == "MyString"
renvoie False
parce que la fonction str.encode()
est renvoyant un objet octets :
In [2]: us.encode('utf-8')
Out[2]: b'MyString'
Dans Python 3, les chaînes sont déjà Unicode , donc le u'MyString'
est superflu.