python - ¿Cómo comparo una cadena Unicode que tiene diferentes bytes, pero el mismo valor?
import unicode python (3)
Estoy comparando cadenas Unicode entre objetos JSON.
Tienen el mismo valor:
a = ''人口じんこうに膾炙かいしゃする''
b = ''人口じんこうに膾炙かいしゃする''
Pero tienen diferentes representaciones Unicode:
String a : u''/u4eba/u53e3/u3058/u3093/u3053/u3046/u306b/u81be/u7099/u304b/u3044/u3057/u3083/u3059/u308b''
String b : u''/u4eba/u53e3/u3058/u3093/u3053/u3046/u306b/u81be/uf9fb/u304b/u3044/u3057/u3083/u3059/u308b''
¿Cómo puedo comparar entre dos cadenas Unicode en su valor?
El personaje
U+F9FB
(炙) es un
ideógrafo de compatibilidad CJK
.
Estos caracteres son puntos de código distintos de los caracteres CJK normales, pero se descomponen en uno o más caracteres CJK normales cuando se normalizan.
Unicode tiene un algoritmo oficial de clasificación de cadenas llamado
UCA
diseñado exactamente para este propósito.
Python no viene con soporte UCA a partir de 3.7,
*
pero hay bibliotecas de terceros como
pyuca
:
>>> from pyuca import Collator
>>> ck = Collator().sort_key
>>> ck(a) == ck(b)
True
Para este caso, y muchos otros, pero definitivamente no todos, elegir la normalización adecuada para aplicar a ambas cadenas antes de comparar funcionará, y tiene la ventaja del soporte integrado en stdlib.
* La idea ha sido aceptada en principio desde 3.4, pero nadie ha escrito una implementación, en parte porque la mayoría de los desarrolladores principales que se preocupan están usando
pyuca
o uno de los dos enlaces de la UCI, que tienen la ventaja de trabajar en versiones actuales y anteriores de pitón.
Hubiera usado PyICU y su clase Collator. Pero primero, debe pensar en qué nivel del algoritmo de clasificación Unicode desea que ocurra la igualdad.
#!/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)))
Esto produce:
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
La normalización Unicode lo llevará allí para esto:
>>> import unicodedata
>>> unicodedata.normalize("NFC", "/uf9fb") == "/u7099"
True
Use
unicodedata.normalize
en ambas cadenas antes de compararlas con
==
para verificar la equivalencia canónica de Unicode.
El personaje
U+F9FB
es un personaje de "Compatibilidad CJK".
Estos caracteres se descomponen en uno o más caracteres CJK normales cuando se normalizan.