Сравнение Python UTF-8 - PullRequest
       28

Сравнение Python UTF-8

17 голосов
/ 03 августа 2010
a = {"a":"çö"}
b = "çö"
a['a']
>>> '\xc3\xa7\xc3\xb6'

b.decode('utf-8') == a['a']
>>> False

Что там происходит?

edit = Извините, это была моя ошибка.Это все еще ложь.Я использую Python 2.6 в Ubuntu 10.04.

Ответы [ 7 ]

28 голосов
/ 04 августа 2010

Возможные решения

Либо напишите так:

a = {"a": u"çö"}
b = "çö"
b.decode('utf-8') == a['a']

Или вот так (вы также можете пропустить .decode('utf-8') с обеих сторон):

a = {"a": "çö"}
b = "çö"
b.decode('utf-8') == a['a'].decode('utf-8')

Или вот так (моя рекомендация):

a = {"a": u"çö"}
b = u"çö"
b == a['a']

Объяснение

Обновлено на основе комментария Тима. В вашем исходном коде, b.decode('utf-8') == u'çö' и a['a'] == 'çö',так что вы на самом деле делаете следующее сравнение:

u'çö' == 'çö'

Один из объектов имеет тип unicode, другой тип str, поэтому для выполнения сравнения str преобразуется в unicode, а затем сравниваются два объекта unicode.Он работает нормально в случае чисто ASCII-строк, например: u'a' == 'a', так как unicode('a') == u'a'.

Однако, это не работает в случае u'çö' == 'çö', так как unicode('çö') возвращает следующую ошибку: UnicodeDecodeError: кодек 'ascii' не может декодировать байт 0xc3 в позиции 0: порядковый номер не находится в диапазоне (128) , и поэтому все сравнение возвращает значение False и выдает следующее предупреждение: UnicodeWarning: сравнение Unicodeне удалось преобразовать оба аргумента в Unicode - интерпретировать их как неравные .

5 голосов
/ 03 августа 2010

b является string, a является dict

Вы хотите (я верю):

b == a['a']

3 голосов
/ 04 августа 2010

UTF-8 - это кодировка, используемая для записи текста Unicode в файлы.Однако в Python вы работаете с объектами, которые имеют фиксированный способ представления текста Unicode, и это не UTF-8.

Вы все равно можете сравнивать строки Unicode в Python, но это не связано с UTF-8, за исключением того, что если вы хотите поместить константы в эти строки Unicode, вам нужно будет кодировать текст файла, содержащего ваш исходный код, в UTF-8.Как только выполняется оператор присваивания, строка больше не является UTF-8, а теперь является внутренним представлением Python.

Кстати, если вы проводите сравнения с Unicode, вам, вероятно, захочется использоватьмодуль unicodedata и нормализуйте строки перед сравнением.

2 голосов
/ 03 августа 2010

Вы сравниваете строку с диктовкой.

>>> a = {"a":"çö"}
>>> b = "çö"
>>> a == b
False
>>> a['a'] == b
True

Если вы сравните строку (b) с членом a (a ['a']), то получите желаемый результат.

2 голосов
/ 03 августа 2010

Попробуйте b == a ['a']

0 голосов
/ 04 августа 2010

NullUserException правильно, что это должно быть правильно:

b == a['a']

Вы по-прежнему получаете «False», потому что вы декодируете одну сторону как utf-8 (создавая строку Unicode), в то время как другая сторона остается закодированной байтовой строкой utf-8.

0 голосов
/ 04 августа 2010

Убедитесь, что ваш код в UTF-8 (НЕ Latin-1) и / или используйте строку кодирования следующим образом:

#! /usr/bin/python
# -*- coding: utf-8 -*-
a = {"a": u"çö"}
b = "çö"
assert b == a['a']
assert b.decode('utf-8') == a['a'].decode('utf-8')

Если вы используете Юникод по всем направлениям, вы можете импортировать unicode_literals из будущего и сократить потери кодирования:

#! /usr/bin/python
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
a = {"a": u"çö"}
b = "çö"
assert b == a['a']
assert b == a['a']
assert b.encode('utf-8') != a['a']
assert b.encode('utf-8') == a['a'].encode('utf-8')

Если файл использует unicode_literals, все «строки» теперь являются объектами «unicode» (в соответствии с кодировкой файла), если они не «b» с префиксом ab (для эмуляции строки / байтов, разделенных в Python 3). .X).

...