Ignorer les accents lors de la comparaison de chaînes en Java

 Article modifié dernièrement le 27 Nov 2016 @ 14 h 06 min

Le problème s’est manifesté dans la « recherche rapide » de cartes sur mon site Magic Supremacy, les joueurs étaient obligé de saisir les accents d’une carte, si celle-ci en comportait, pour que le système la retrouve correctement et la propose dans sa liste de résultats possibles.

Exemple, si nous commencions à saisir « Viande frai », la carte française nommée « Viande fraîche » (avec un i circonflexe) n’était pas proposée. La raison est tout simplement due à l’utilisation de la méthode startsWith() de la classe java.lang.String pour comparer les noms de cartes et ça se comprend car après tout le i et le î sont différents, ainsi que le e et le é, ou le u et le ü, cependant ce n’est pas pratique de devoir taper les accents pour retrouver une carte en particulier, j’ai donc dû trouver un moyen pour satisfaire mes joueurs ^^

Je suis tombé sur la classe java.text.Collator qui de prime à bord semblait faire exactement ce que je voulais puis finalement je me suis plutôt tourné vers une méthode plus manuelle pour des questions de performance.

Voici trois solutions testées pour l’occasion.

Collator

Cette classe permet de déterminer si les caractères accentués doivent être considéré comme des caractères non-accentués ou si les caractères majuscules doivent être considéré comme des caractères minuscules. Ce niveau  de comparaison est paramétré grâce aux constantes suivantes de la classe : PRIMARY, SECONDARY, TERTIARY ou IDENTICAL, la Locale rentrant aussi en considération. Cette classe était donc faite pour moi.

Cependant les méthodes de cette classe sont assez limitées, il n’y a quasiment que le compare() qui ne m’aide pas étant donné que je souhaite comparer les chaines de caractères qui commencent par une autre (le startsWith).

Déception et abandon de cette solution.

Normalizer

L’idée a été ensuite de trouver un moyen de transformer en amont les chaînes à comparer, pour ensuite utiliser le startsWith(). Les caractères accentués doivent être converti en leurs caractères non-accentués équivalent (é -> e, ü -> u, î -> i, etc.) ainsi que les majuscules en minuscules (E -> e, Ü -> u, etc.).

La classe java.text.Normalizer s’occupe très bien de la conversion des accents et pour les majuscules un simple toLowerCase() permet de s’en arranger :

Ainsi la recherche du nom « Viande fraîche » ou « viande fraiche » parmis tous les noms de cartes disponibles sera équivalente en appliquant cette méthode au nom de la carte à chercher ET au nom des cartes à comparer.

Méthode maison

Plus les chaînes de caractères sont longues, plus la transformation des accents avec Normalizer prend du temps, de même qu’un grand nombre d’exécution successive de la méthode formatStringNormalizer() met un certain temps.

J’ai donc décidé d’utiliser une méthode non disponible dans la JRE qui permet à la fois de convertir les accents en non-accent et les majuscules en minuscules, une méthode fort appréciable car environ 8x plus rapide, trouvée à cette adresse.

Temps d’exécution

Voici la façon utilisée pour me rendre compte que la méthode formatStringNormalizer() est plus lente que la méthode formatStringManual() :

Trois flèches vers le bas

1- Logiciel de brouillage d’adresse IP :

Contourner la censure en surfant anonyme

2- L’article explicatif :

La différence entre un proxy et un VPN

3- Comment espionner un smartphone (app) :

L’application de référence

Commentez ici

  • Greg 2 septembre 2011, 17 05

    Article intéressant. Ça me rappelle la première fois que j’ai voulu convertir un texte français en un même texte sans accent, c’est-à-dire en remplaçant les é en e, à en a, etc. Certes on peut le faire avec la méthode « rechercher/remplacer » mais c’est long. J’ai finalement trouvé la solution sous Word qui est de convertir le texte en .txt brut, choisir « autre codage » puis « ASCII » tout en cochant la case pour autoriser le remplacement de caractère.

  • Gérald 2 février 2012, 9 09

    Merci pour cet article qui permet de connaitre rapidement plusieurs alternatives au problème de la conversion des caractères accentués. Dans mon cas, la performance n’est pas un problème, et le Normalizer de Java fait très bien le boulot, y compris pour d’autres caractères accentués non pris en charge par la méthode ‘maison’ (mais improbables en français, comme le úòó, etc).

Article suivant:

Article précédent:

Share This