PROJET AUTOBLOG


Sam et Max

source: Sam et Max

⇐ retour index

Transformer des caractères spéciaux en ASCII

samedi 1 décembre 2012 à 15:23

Dans beaucoup de cas, plutôt que de se taper la gestion de l’encodage, on préfère tout ramener au plus petit dénominateur commun: l’ASCII. Pas d’accent, pas de problème, comme disait mon grand-père juif. Ça devait être un autre contexte. Mais quand même.

Remplacer les accents par leurs équivalents ASCII les plus proches

Une astuce que j’ai lue pour la toute première fois dans les excellents snippets Python de Sauvage (encore et toujours…).

>>> import unicodedata
>>> chaine_unicode = u"Vous êtes le Père Noël ? s'étonna le petit garçon."
>>> unicodedata.normalize('NFKD', chaine_unicode).encode('ascii', 'ignore')
"Vous etes le Pere Noel ? s'etonna le petit garcon."

Si un caractère n’est pas vraiment remplaçable, on peut choisir plusieurs stratégies. Ignorer le caractère:

>>> unicodedata.normalize('NFKD', u"Bei Jing en chinois s'écrit 北亰").encode('ascii', 'ignore')
"Bei Jing en chinois s'ecrit "

Remplacer le caractère par un point d’interrogation:

>>> unicodedata.normalize('NFKD', u"Bei Jing en chinois s'écrit 北亰").encode('ascii', 'replace')
"Bei Jing en chinois s'e?crit ??"

Notez l’effet sur le caractère accentué…

Ou se vautrer comme une grosse loutre bourrée à la bière:

>>> unicodedata.normalize('NFKD', u"Bei Jing en chinois s'écrit 北亰").encode('ascii')
Traceback (most recent call last):
  File "<ipython-input-21-24181c80fc7f>", line 1, in <module>
    unicodedata.normalize('NFKD', u"Bei Jing en chinois s'écrit 北亰").encode('ascii')
UnicodeEncodeError: 'ascii' codec can't encode character u'\u0301' in position 23: ordinal not in range(128)

Ce qui pour nous a un intérêt limité.

Certains alphabets, comme le hongrois, ont des caractères qui pourraient être extrapolés vers l’ASCII, mais la normalisation NFKD ne le permet pas. On peut alors faire appel à une bibliothèque externe.

Unidecode, la cafetière de l’encoding

Unidecode est une lib pip installable qui permet la translittération de caractères. Ce n’est pas toujours très rigoureux, mais c’est toujours très pratique.

Par exemple, vous voulez créer un site Web de mode à destination du marché Hongrois. Si, si. C’est un marché en pleine expansion, j’vous dis.

Et bien entendu vous avez une rubrique manteau, qui se dit en hongrois, comme nous le savons tous: “kožušček”.

Bon, si vous essayé de mettre ça en slug dans vos URL, ça va être un peu chiant à taper, et malheureusement l’astuce précédente ne va pas vous aider:

In [5]: unicodedata.normalize('NFKD', u"kožušček").encode('ascii', 'replace')
Out[5]: 'koz?us?c?ek'

Partant de là, vous pouvez soit:

In [7]: from unidecode import unidecode
In [8]: unidecode(u"kožušček")
Out[8]: 'kozuscek'

Encore plus fastoche, dans le XML et HTML

Dans ces formats à balise, on peut s’affranchir des problème d’encodage en transformant chaque caractère en une entité XML / HTML. On récupère alors du texte ASCII et le client se tapera le boulot d’afficher tous les caractères tordus auxquels l’humanité a pu penser:

In [11]: print u"Le Père Noël m'a offert un kožušček à 北亰".encode('ascii', 'xmlcharrefreplace')
Le P&#232;re No&#235;l m'a offert un ko&#382;u&#353;&#269;ek &#224; &#21271;&#20144;

Et dans tous les autres cas ?

Ben c’est comme d’hab: str.decode() pour tout ce qui rentre pour récupérer une chaîne unicode, et unicode.encode() pour tout ce qui sort pour rebalancer une chaîne de caractères au monde extérieur.

Ça mérite peut être un article d’ailleurs…

P.S: Lazarus vient de me sauver la mise en restaurant cet article suite à un clic malheureux. Vive lazarus.