|
Comparer des chaînes avec lettres accentuées |
Niveau : débutant/initié
Compatibilité : Java 1.1 et ultérieureIl arrive souvent d'avoir à effectuer des comparaisons de chaînes de caractères qui ne prennent pas en compte les combinaisons de majuscules/minuscules, mais aussi qui doivent ignorer la différence entre caractères accentués et non accentués. Ceci est très utile pour effectuer par exemple des tris sur des noms.
Le package java.text fournit la classe Collator prévue à cet effet : pour chaque langue, cette classe permet d'effectuer des comparaisons plus ou moins strictes entre deux chaînes de caractères grâce à la méthode setStrength (). Cette méthode peut prendre en paramètre une des valeurs suivantes :
Collator.PRIMARY
Comparaison la moins stricte : une même lettre qu'elle soit majuscule, minuscule ou accentuée est considérée comme identique.
Collator.SECONDARY
Comparaison majuscule/minuscule : une lettre majuscule est identique à sa minuscule, mais différente des lettres accentuées.
Collator.TERTIARY
Comparaison la plus stricte : toutes les lettres sont différentes.
Une fois choisi le niveau de comparaison, il suffit d'utiliser la méthode compare () pour comparer deux chaînes de caractères. Cette méthode renvoie 0 si les deux chaînes sont identiques.
Voici l'exemple d'application CompareTest permettant de tester la classe Collator. Recopiez-le dans un fichier CompareTest.java, compilez-le avec la commande javac CompareTest.java et exécutez-le grâce à la commande java CompareTest :
import java.text.Collator; import java.util.Locale; public class CompareTest { public static void main (String args []) { // Instantiation d'un collator français Collator compareOperator = Collator.getInstance (Locale.FRENCH); // Comparaison sans tenir compte des accents compareOperator.setStrength (Collator.PRIMARY); System.out.println ("Comparaison strength = PRIMARY"); showComparison (compareOperator); // Comparaison sans tenir compte des majuscules/minuscules compareOperator.setStrength (Collator.SECONDARY); System.out.println ("\nComparaison strength = SECONDARY"); showComparison (compareOperator); // Comparaison strict compareOperator.setStrength (Collator.TERTIARY); System.out.println ("\nComparaison strength = TERTIARY"); showComparison (compareOperator); } private static void showComparison (Collator compareOperator) { String string1 = "ABCDEF"; String [] comparedStrings = {"ABCDEF", "Abcdef", "\u00e0b\u00e7def"}; for (int i = 0; i < comparedStrings.length; i++) { int result = compareOperator.compare (string1, comparedStrings [i]); System.out.println ( " " + string1 + " et " + comparedStrings [i] + (result == 0 ? " identiques" : " diff\u00e9rents")); } } }L'exécution de ce programme donne les résultats suivants :
Comparaison strength = PRIMARY ABCDEF et ABCDEF identiques ABCDEF et Abcdef identiques ABCDEF et àbçdef identiques Comparaison strength = SECONDARY ABCDEF et ABCDEF identiques ABCDEF et Abcdef identiques ABCDEF et àbçdef différents Comparaison strength = TERTIARY ABCDEF et ABCDEF identiques ABCDEF et Abcdef différents ABCDEF et àbçdef différents
La classe Collator est très pratique pour comparer des chaînes de caractères dans différentes langues. Mais si vous devez effectuer des comparaisons très nombreuses comme le fait un moteur de recherche, il existe d'autres façons plus restrictives mais plus rapides d'opérer.
Pour rechercher une sous-chaîne dans une chaîne de caractères sans tenir compte des minuscules/majuscules et des caractères accentués, il est possible d'opérer des deux manières suivantes :
- Utiliser la méthode compare () de la classe Collator, pour comparer la sous-chaîne recherchée à chacune des sous-chaînes possibles du texte à parcourir.
- Rechercher avec la méthode indexOf () de la classe String la sous-chaine dans le texte à parcourir, en convertissant d'abord les deux chaînes en minuscules sans accent.
La première méthode devant créer de nombreuses sous-chaînes est très pénalisante, comme le prouve l'exemple SearchTest suivant. Recopiez-le dans un fichier SearchTest.java, compilez-le avec la commande javac SearchTest.java et exécutez-le grâce à la commande java SearchTest :
import java.text.Collator; import java.util.Locale; public class SearchTest { public static void main (String args []) { String search = "TEXT"; // Fabrication d'un très long texte String text = "Un "; for (int i = 0; i < 1000; i++) text += "tr\u00e8s "; text += "long t\u00e8xte"; long time = System.currentTimeMillis (); // Instantiation d'un collator français Collator compareOperator = Collator.getInstance (Locale.FRENCH); compareOperator.setStrength (Collator.PRIMARY); // Recherche de la sous-chaîne search dans text int searchLength = search.length (); int max = text.length () - searchLength; int index = -1; for (int i = 0; i < max; i++) if (compareOperator.compare (text.substring (i, searchLength++), search) == 0) { index = i; break; } // Affichage du temps écoulé System.out.println ("Trouv\u00e9 avec Collator \u00e0 l'indice " + index + " apr\u00e8s " + (System.currentTimeMillis () - time) + " ms"); time = System.currentTimeMillis (); // Conversion des deux chaînes en minuscules sans accents // avec le convertisseur ci-dessous String lowerCaseText = toLowerCase (text); String lowerCaseSearch = toLowerCase (search); // Recherche de la sous-chaine lowerCaseSearch dans lowerCaseText index = lowerCaseText.indexOf (lowerCaseSearch); // Affichage du temps écoulé System.out.println ("Trouv\u00e9 avec toLowerCase () et indexOf \u00e0 l'indice " + index + " apr\u00e8s " + (System.currentTimeMillis () - time) + " ms"); } // Conversion des caractères d'une chaine en minuscules sans accents static public String toLowerCase (String string) { char [] charsData = new char [string.length ()]; string.getChars (0, charsData.length, charsData, 0); char c; for (int i = 0; i < charsData.length; i++) if ( (c = charsData [i]) >= 'A' && c <= 'Z') charsData [i] = (char)(c - 'A' + 'a'); else switch (c) { case '\u00e0' : case '\u00e2' : case '\u00e4' : charsData [i] = 'a'; break; case '\u00e7' : charsData [i] = 'c'; break; case '\u00e8' : case '\u00e9' : case '\u00ea' : case '\u00eb' : charsData [i] = 'e'; break; case '\u00ee' : case '\u00ef' : charsData [i] = 'i'; break; case '\u00f4' : case '\u00f6' : charsData [i] = 'o'; break; case '\u00f9' : case '\u00fb' : case '\u00fc' : charsData [i] = 'u'; break; } return new String (charsData); } }L'exécution de ce programme donne des résultats différents suivant la puissance de votre machine. Voici le résultat obtenu sur un Macintosh équipé d'un PowerPC 233 MHz :
Trouvé avec Collator à l'indice 5008 après 9085 ms Trouvé avec toLowerCase () et indexOf à l'indice 5008 après 10 msUn rapport de 1 à 1000 !
La version de la méthode toLowerCase () de la classe String utilisant comme paramètre une instance de la classe Locale ne convertit pas les lettres accentuées et reste plus lente que la méthode décrite ci-dessus.
|