web-dev-qa-db-fra.com

Normalisation Unicode

Existe-t-il un moyen standard, en Python, de normaliser une chaîne unicode, afin qu'elle ne comprenne que les entités unicode les plus simples pouvant être utilisées pour la représenter?

Je veux dire, quelque chose qui traduirait une séquence comme ['LATIN SMALL LETTER A', 'COMBINING ACUTE ACCENT'] à ['LATIN SMALL LETTER A WITH ACUTE']?

Voyez où est le problème:

>>> import unicodedata
>>> char = "á"
>>> len(char)
1
>>> [ unicodedata.name(c) for c in char ]
['LATIN SMALL LETTER A WITH ACUTE']

Mais maintenant:

>>> char = "á"
>>> len(char)
2
>>> [ unicodedata.name(c) for c in char ]
['LATIN SMALL LETTER A', 'COMBINING ACUTE ACCENT']

Je pourrais, bien sûr, parcourir tous les caractères et faire des remplacements manuels, etc., mais ce n'est pas efficace, et je suis presque sûr que je manquerais la moitié des cas spéciaux et ferais des erreurs.

55
michaelmeyer

Le module unicodedata propose une fonction .normalize() , que vous souhaitez normaliser au format NFC:

>>> unicodedata.normalize('NFC', u'\u0061\u0301')
u'\xe1'
>>> unicodedata.normalize('NFD', u'\u00e1')
u'a\u0301'

NFC, ou "Forme normale composée" renvoie des caractères composés, NFD, "Forme normale décomposée" vous donne des caractères combinés décomposés.

Les formulaires NFKC et NFKD supplémentaires traitent des points de code de compatibilité; par exemple. U + 2160 (ROMAN NUMERAL ONE) est vraiment la même chose que U + 0049 (LATIN CAPITAL LETTER I) mais présente dans la norme Unicode pour rester compatible avec les encodages qui les traitent séparément. L'utilisation de la forme NFKC ou NFKD, en plus de composer ou de décomposer des caractères, remplacera également tous les caractères de "compatibilité" par leur forme canonique:

>>> unicodedata.normalize('NFC', u'\u2167')  # roman numeral VIII
u'\u2167'
>>> unicodedata.normalize('NFKC', u'\u2167') # roman numeral VIII
u'VIII'

Notez qu'il n'y a aucune garantie que les formes composées et décomposées sont communicatives; normaliser un caractère combiné en NFC, puis reconvertir le résultat au format NFD n'entraîne pas toujours la même séquence de caractères. La norme Unicode conserve une liste d'exceptions ; les caractères de cette liste sont composables, mais pas décomposables dans leur forme combinée, pour diverses raisons. Voir également la documentation sur le Composition Exclusion Table .

81
Martijn Pieters

Oui, il y a .

unicodedata.normalize(form, unistr)

Vous devez sélectionner l'un des quatre formulaires de normalisation .

7
SLaks