Подтвердить что ты не робот

Как я могу сравнить тип unicode с строкой в ​​python?

Я пытаюсь использовать понимание списка, которое сравнивает строковые объекты, но одна из строк - utf-8, побочный продукт json.loads. Сценарий:

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

Первая часть моего вопроса, почему это возвращает False?

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

Часть вторая - как я могу сравнивать в понимании списка?

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

EDIT: я использую Google App Engine, который использует Python 2.7

Здесь приведен более полный пример проблемы:

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

Ответ 1

Вы должны зацикливаться на неправильном наборе данных; просто зациклите прямо на словарь, загруженный 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 есть строка не строка UTF-8; это данные в формате unicode, библиотека json уже расшифровала его для вас. С другой стороны, строка UTF-8 представляет собой байты с кодировкой последовательности. Вы можете прочитать на Unicode и Python, чтобы понять разницу:

На 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 для сравнения; Вместо этого используйте литералы в формате unicode:

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

Ответ 2

Вы пытаетесь сравнить строку байтов ('MyString') со строкой кодовых точек Unicode (u'MyString'). Это сравнение "яблоки и апельсины". К сожалению, Python 2 в некоторых случаях делает вид, что это сравнение действительно, вместо того, чтобы всегда возвращать False:

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

Это зависит от вас как разработчика/разработчика, чтобы решить, какое должно быть правильное сравнение. Вот один из возможных способов:

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

Я рекомендую выше, а не a == b.decode('UTF-8'), потому что все строки стиля u'' могут быть закодированы в байты с UTF-8, за исключением, возможно, в некоторых странных случаях, но не все байтовые строки могут быть декодированы в Unicode таким образом.

Но если вы решите сделать кодировку UTF-8 строк Unicode перед сравнением, это приведет к сбою для чего-то подобного в системе Windows: u'Em dashes\u2014are cool'.encode('UTF-8') == 'Em dashes\x97are cool'. Но если вы .encode('Windows-1252'), то это сработает. Вот почему это сравнение яблок и апельсинов.

Ответ 3

Я предполагаю, что вы используете Python 3. us.encode('utf-8') == "MyString" возвращает False, потому что функция str.encode() возвращает объект байтов:

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

В Python 3 строки уже Unicode, поэтому u'MyString' является излишним.