Bonjour,

A la recherche d'une méthode pour supprimer les accents d'une chaine de caractère afin de faciliter la comparaison entre 2 chaînes, j'ai implémenter plusieurs solutions et me suis intéressé aux performances.

Comme j'ai relevé des différences notables entre ces solutions et entre les versions du Framework, je me suis dit que cela pourrait interesser d'autres développeurs

Voici le code que j'utilise en boucle (> 40000 itérations) et plusieurs fois dans une autre methode pour comparer les resultats.

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
       public static string RemoveDiacritics(string inputString)
        {
            string result = inputString.Trim().ToLower();
            // nothing: algo takes 2,06 s
            //string res0 = result;
            // Method1: String.Replace   -> 2,28s 
            //string res1 = RemoveDiacriticsStringReplace(result);
            // Method2: char replace + string builder -> 2,25s
            //string res2 = RemoveDiacriticsCharReplace(result);
            // Method3: Regex.Replace -> 5,8 s -> 2 times slower
            //string res3 = RemoveDiacriticsRegex(result);
            // Method4, need .NET 2.0: normalization -> 2,28 s
            string res4 = RemoveDiacriticsNormalizationDotNet2(result);
            //Debug.Assert(res1 == res2 && res1 == res3 && res1 == res4 && res2 == res3 && res2 == res4 && res3 == res4);
            return res4;
        }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
 
        public static string RemoveDiacriticsStringReplace(string inputString)
        {
            string result = inputString;
            result = result.Replace('à', 'a');
            result = result.Replace('á', 'a');
            result = result.Replace('ä', 'a');
            result = result.Replace('â', 'a');
            result = result.Replace('ã', 'a');
            result = result.Replace('å', 'a');
            result = result.Replace('é', 'e');
            result = result.Replace('è', 'e');
            result = result.Replace('ê', 'e');
            result = result.Replace('ë', 'e');
            result = result.Replace('ì', 'i');
            result = result.Replace('í', 'i');
            result = result.Replace('ï', 'i');
            result = result.Replace('î', 'i');
            result = result.Replace('ò', 'o');
            result = result.Replace('ó', 'o');
            result = result.Replace('ô', 'o');
            result = result.Replace('ö', 'o');
            result = result.Replace('û', 'u');
            result = result.Replace('ü', 'u');
            result = result.Replace('ù', 'u');
            result = result.Replace('ú', 'u');
            result = result.Replace('ý', 'y');
            result = result.Replace('ÿ', 'y');
            result = result.Replace('ç', 'c');
            result = result.Replace('ñ', 'n');            
            return result;
        }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 
        public static string RemoveDiacriticsCharReplace(string inputString)
        {
            string result;
            StringBuilder builder = new StringBuilder();
            char[] car = inputString.ToCharArray();
            foreach (char c in car)
            {
                if (c == 'ä' || c == 'á' || c == 'à' || c == 'â' || c == 'ã' || c == 'å')
                    builder.Append('a');
                else if (c == 'é' || c == 'è' || c == 'ê' || c == 'ë')
                    builder.Append('e');
                else if (c == 'ì' || c == 'í' || c == 'ï' || c == 'î')
                    builder.Append('i');
                else if (c == 'ò' || c == 'ó' || c == 'ô' || c == 'ö')
                    builder.Append('o');
                else if (c == 'ù' || c == 'ú' || c == 'ü' || c == 'û')
                    builder.Append('u');
                else if (c == 'ÿ' || c == 'ý')
                    builder.Append('y');
                else if (c == 'ç')
                    builder.Append('c');
                else if (c == 'ñ')
                    builder.Append('n');
                else builder.Append(c);
            }
            result = builder.ToString();
            return result;
        }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
        public static string RemoveDiacriticsRegex(string inputString)
        {
            string result = inputString;
            result = System.Text.RegularExpressions.Regex.Replace(result, @"(à|á|ä|â|ã|å)+", "a");
            result = System.Text.RegularExpressions.Regex.Replace(result, @"(é|è|ê|ë)+", "e");
            result = System.Text.RegularExpressions.Regex.Replace(result, @"(ì|í|ï|î)+", "i");
            result = System.Text.RegularExpressions.Regex.Replace(result, @"(ò|ó|ö|ô)+", "o");
            result = System.Text.RegularExpressions.Regex.Replace(result, @"(ü|û|ù|ú)+", "u");
            result = System.Text.RegularExpressions.Regex.Replace(result, @"(ÿ|ý)+", "y");
            result = System.Text.RegularExpressions.Regex.Replace(result, @"(ç)+", "c");
            result = System.Text.RegularExpressions.Regex.Replace(result, @"(ñ)+", "n");
            return result;
        }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
        public static string RemoveDiacriticsNormalizationDotNet2(string inputString)
        {
            string result = inputString;
            String normalizedString = result.Normalize(NormalizationForm.FormD);
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < normalizedString.Length; i++)
            {
                Char c = normalizedString[i];
                if (CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark)
                    stringBuilder.Append(c);
            }
            result = stringBuilder.ToString();
            return result;
        }
Et voici les résultats en temps d'exécution (secondes): j'ai juste changé les commentaires dans ma méthode principale RemoveDiacritics.
Et j'ai compilé mon code sous VS2003 aussi bien que sous VS2005.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
                .net2     .net1.1
rien            2,06      1,85
string replace  2,28      2,41      
char replace    2,25      2,15
regex           5,8      22 !!
normalization   2,28      n/a
J'ai lancé chq test 4-5 fois et fait la moyenne ici.

Deux points particulièrement intéressant concernant les Regex:
1) c'est plus lent que des simples Replace
2) cela a été drolement bien amélioré dans le .NET 2.0 !
-> les regex sont 2 fois plus lentes que des replaces en .NET 2.0 mais 10 fois plus lentes en 1.1!

Petite remarque sur mes regex: elles ne sont pas tout à fait correctes puisqu'elles remplacent par ex un "éé" en "e" au lieu de "ee".

Enfin, la seule méthode qui soit complète est celle utilisant les classes Normalization et CharUnicodeInfo. Les autres sont du manuels où j'ai mis seulement les élements nécessaires (via mon Assert).

Que dites vous de tels résultats? Impressionnants qd meme, non?