¿Cómo puedo comparar un tipo Unicode con una cadena en Python?

Estoy tratando de usar una lista de comprensión que compara los objetos de cadena, pero una de las cadenas es utf-8, el subproducto de json.loads. Guión:

us = u'MyString' # is the utf-8 string 

La primera parte de mi pregunta es ¿por qué esto devuelve Falso? :

 us.encode('utf-8') == "MyString" ## False 

Parte dos: ¿Cómo puedo comparar dentro de una lista de comprensión?

 myComp = [utfString for utfString in jsonLoadsObj if utfString.encode('utf-8') == "MyString"] #wrapped to read on SO 

EDITAR: Estoy usando Google App Engine, que usa Python 2.7

Aquí hay un ejemplo más completo del problema:

 #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"] 

Debe hacer un bucle sobre el conjunto de datos incorrecto; simplemente haga un bucle directamente sobre el diccionario cargado con JSON, no es necesario llamar a .keys() primero:

 data = json.loads(response) myList = [item for item in data if item == "number1"] 

Es posible que desee utilizar u"number1" para evitar conversiones implícitas entre Unicode y cadenas de bytes:

 data = json.loads(response) myList = [item for item in data if item == u"number1"] 

Ambas versiones funcionan 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'] 

Tenga en cuenta que en su primer ejemplo, us no es una cadena UTF-8; son datos Unicode, la biblioteca json ya lo ha decodificado por ti. Una cadena UTF-8, por otro lado, es una secuencia codificada en bytes . Es posible que desee leer sobre Unicode y Python para comprender la diferencia:

  • El Absoluto Mínimo que todos los desarrolladores de software absolutamente, positivamente deben saber sobre Unicode y conjuntos de caracteres (¡sin excusas!) Por Joel Spolsky

  • El CÓMO de Python Unicode

  • Unicode pragmático de Ned Batchelder

En Python 2, tu expectativa de que tu prueba devuelva True sería correcto, estás haciendo algo incorrecto:

 >>> us = u'MyString' >>> us u'MyString' >>> type(us)  >>> us.encode('utf8') == 'MyString' True >>> type(us.encode('utf8'))  

No es necesario codificar las cadenas en UTF-8 para hacer comparaciones; usa literales Unicode en su lugar:

 myComp = [elem for elem in json_data if elem == u"MyString"] 

Está intentando comparar una cadena de bytes ( 'MyString' ) con una cadena de puntos de código Unicode ( u'MyString' ). Esta es una comparación de “manzanas y naranjas”. Desafortunadamente, Python 2 pretende en algunos casos que esta comparación es válida, en lugar de devolver siempre False :

 >>> u'MyString' == 'MyString' # in my opinion should be False True 

Depende de usted como diseñador / desarrollador para decidir cuál debe ser la comparación correcta. Aquí hay una manera posible:

 a = u'MyString' b = 'MyString' a.encode('UTF-8') == b # True 

Recomiendo lo anterior en lugar de a == b.decode('UTF-8') porque todas u'' cadenas de estilo u'' pueden codificarse en bytes con UTF-8, excepto posiblemente en algunos casos extraños, pero no todas las cadenas de bytes pueden Se decodificará a Unicode de esa manera.

Pero si elige hacer una encoding UTF-8 de las cadenas Unicode antes de comparar, fallará algo como esto en un sistema Windows: u'Em dashes\u2014are cool'.encode('UTF-8') == 'Em dashes\x97are cool' . Pero si .encode('Windows-1252') en su lugar, tendría éxito. Es por eso que es una comparación de manzanas y naranjas.

Supongo que estás usando Python 3. us.encode('utf-8') == "MyString" devuelve False porque la función str.encode() está devolviendo un objeto de bytes :

 In [2]: us.encode('utf-8') Out[2]: b'MyString' 

En Python 3, las cadenas ya son Unicode , por lo que u'MyString' es superflua.