Как сравнить строку Юникода, которая имеет разные байты, но одно и то же значение?



я сравниваю строки Юникода между объектами JSON.



Они имеют одинаковое значение:



a = '人口じんこうに膾炙かいしゃする'
b = '人口じんこうに膾炙かいしゃする'


но у них разные представления Юникода:



String a : u'u4ebau53e3u3058u3093u3053u3046u306bu81beu7099u304bu3044u3057u3083u3059u308b'
String b : u'u4ebau53e3u3058u3093u3053u3046u306bu81beuf9fbu304bu3044u3057u3083u3059u308b'


Как я могу сравнить между двумя строками Юникода по их значению?

647   3  

3 ответов:

нормализации Unicode доставит вас туда для этого:

>>> import unicodedata
>>> unicodedata.normalize("NFC", "\uf9fb") == "\u7099"
True

использовать unicodedata.normalize на обеих ваших строках, прежде чем сравнивать их с == для проверки канонической эквивалентности Юникода.

символ U+F9FB "совместимость дальневосточные" характер. Эти символы при нормализации разлагаются на один или несколько обычных символов CJK.

символ U+F9FB (炙) - это CJK совместимость Ideograph. Эти символы являются отдельными кодовыми точками от обычных символов CJK, но при нормализации они разлагаются на один или несколько обычных символов CJK.

Unicode имеет официальный алгоритм сортировки строк под названием UCA предназначен именно для этой цели. Python не поставляется с поддержкой UCA по состоянию на 3.7,* но есть сторонние библиотеки, такие как pyuca:

>>> from pyuca import Collator
>>> ck = Collator().sort_key
>>> ck(a) == ck(b)
True

для этого случая-и многих других, но определенно не всех-подбираем подходящий нормализация чтобы применить к обеим строкам перед сравнением будет работать, и он имеет преимущество поддержки, встроенной в stdlib.

* идея была в принципе согласна с 3.4, но никто не написал реализацию-отчасти потому, что большинство основных разработчиков, которые заботятся используете pyuca или одна из двух Привязок ICU, которая преимущество работы в текущих и старых версий Python.

Я бы использовал PyICU и его класс Collator. Но сначала вы должны подумать, на каком уровне алгоритм сортировки Юникода вы хотите, чтобы равенство получилось.

#!/usr/bin/python
# -*- coding: utf-8 -*-

from icu import Collator

coll = Collator.createInstance()
coll.setStrength(Collator.IDENTICAL)

a = u'人口じんこうに膾炙かいしゃする'
b = u'人口じんこうに膾炙かいしゃする'
print repr(a)
print repr(b)
print ('%s == %s : %s' % (a, b, coll.equals(a,b)))

a = u'エレベーター'
b = u'エレベーター'
print ('%s == %s : %s' % (a, b, coll.equals(a,b)))

coll.setStrength(Collator.PRIMARY)
print ('%s == %s : %s' % (a, b, coll.equals(a,b)))

a = u'hello'
b = u'HELLO'
coll.setStrength(Collator.PRIMARY)
print ('%s == %s : %s' % (a, b, coll.equals(a,b)))

coll.setStrength(Collator.TERTIARY)
print ('%s == %s : %s' % (a, b, coll.equals(a,b)))

вот результаты:

u'\u4eba\u53e3\u3058\u3093\u3053\u3046\u306b\u81be\u7099\u304b\u3044\u3057\u3083\u3059\u308b'
u'\u4eba\u53e3\u3058\u3093\u3053\u3046\u306b\u81be\uf9fb\u304b\u3044\u3057\u3083\u3059\u308b'
人口じんこうに膾炙かいしゃする == 人口じんこうに膾炙かいしゃする : True
エレベーター == エレベーター : False
エレベーター == エレベーター : True
hello == HELLO : True
hello == HELLO : False

Comments

    Ничего не найдено.