Dos cadenas de Unicode aparentemente idénticas resultan ser diferentes cuando se usa repr (), pero ¿cómo puedo solucionar esto?

Tengo dos listas de cadenas de Unicode, una que contiene palabras recogidas de un archivo de texto, otra que contiene una lista de nombres de archivos de sonido de un directorio, eliminada de su extensión. Algunas de las palabras en una lista son las mismas que las de la otra. Intenté encontrar las coincidencias usando re.search(ur'(?iu)\b%s\b' % string1, string2) string1, string2 re.search(ur'(?iu)\b%s\b' % string1, string2) , fnmatch e incluso simples comparaciones de tipo string1 == string2 , todo lo cual funcionó al escribir el primer me enlisto para las pruebas, pero falló al usar la lista real de palabras recuperadas de un archivo de texto.

Mientras realizaba una prueba para averiguar por qué, chào palabra vietnamita chào , presente en ambas listas. El uso de isinstance(string, unicode) confirmó que ambos eran unicode. Sin embargo, el uso de repr() en ambas cadenas devolvió u'ch\xe0o' en un caso y u'cha\u0300o' en el otro. Así que está bastante claro por qué no van a coincidir.

Parece que encontré la causa, pero no estoy seguro de cómo solucionarlo. Intenté usar .decode('utf-8') ya que pensé que \xe0 podría ser utf-8. Pero todo lo que hizo fue devolver un error de encoding Unicode. Además, si ambas cadenas son unicode y representan la misma palabra, ¿no deberían ser las mismas? Hacer print('%s Vs. %s' % (string1, string2)) devuelve chào Vs. chào chào Vs. chào estoy un poco perdido aquí.

Muchas gracias de antemano por su ayuda.

Algunos caracteres Unicode se pueden especificar de diferentes maneras, como lo ha descubierto, ya sea como un solo punto de código o como un punto de código regular más un punto de código de combinación. El carácter \u0300 es un \u0300 GRAVE COMBINADO , que agrega una marca de acento al carácter anterior.

El proceso de fijar una cadena a una representación común se llama normalización . Puedes usar el módulo unicodedata para hacer esto:

 def n(str): return unicodedata.normalize('NFKC', str) >>> n(u'ch\xe0o') == n(u'cha\u0300o') True 

El problema parece estar en una representación ambigua de acentos graves en Unicode. Aquí está la LETRA A LATINA PEQUEÑA CON GRAVE y aquí está COMBINANDO GRAVE ACCENT que cuando se combina con ‘a’ se convierte más o menos en el mismo carácter que el primero. Así que dos representaciones del mismo personaje. De hecho, Unicode tiene un término para esto: equivalencia de Unicode .

Para implementar esto en Python, use unicodedata.normalize en la cadena antes de comparar. Probé el modo ‘NFC’ que devuelve u’ch \ xe0o ‘para ambas cadenas.