Как я могу сравнить тип 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"]
Ответы
Ответ 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'
является излишним.