web-dev-qa-db-fra.com

Comment puis-je comparer un type Unicode à une chaîne en python?

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"]
34
rGil

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:

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"]
21
Martijn Pieters

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.

12
wberry

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.

3
MattDMo