Как сравнить строку Юникода, которая имеет разные байты, но одно и то же значение?
я сравниваю строки Юникода между объектами JSON.
Они имеют одинаковое значение:
a = '人口じんこうに膾炙かいしゃする'
b = '人口じんこうに膾炙かいしゃする'
но у них разные представления Юникода:
String a : u'u4ebau53e3u3058u3093u3053u3046u306bu81beu7099u304bu3044u3057u3083u3059u308b'
String b : u'u4ebau53e3u3058u3093u3053u3046u306bu81beuf9fbu304bu3044u3057u3083u3059u308b'
Как я могу сравнить между двумя строками Юникода по их значению?
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