Page d'accueilFindIt !ContactAstuces JavaAstuces Java

Astuces JavaTM

Astuces Java

Tip

 Comparer des chaînes avec lettres accentuées

 

Niveau : débutant/initié
Compatibilité : Java 1.1 et ultérieure

Il 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 :

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 ms

Un 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.

 


Page d'accueilFindIt !ContactAstuces JavaAstuces JavaDébut de la page
© Copyrights 1997-2015 Emmanuel PUYBARET / eTeks
- Tous droits réservés -
Astuces Java