312 votes

Le moyen le plus efficace de supprimer les caractères spéciaux d'une chaîne de caractères

Je veux supprimer tous les caractères spéciaux d'une chaîne de caractères. Les caractères autorisés sont A-Z (majuscules ou minuscules), les chiffres (0-9), le trait de soulignement (_) ou le signe point (.).

J'ai ce qui suit, cela fonctionne mais je soupçonne (je sais !) que ce n'est pas très efficace :

    public static string RemoveSpecialCharacters(string str)
    {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < str.Length; i++)
        {
            if ((str[i] >= '0' && str[i] <= '9')
                || (str[i] >= 'A' && str[i] <= 'z'
                    || (str[i] == '.' || str[i] == '_')))
                {
                    sb.Append(str[i]);
                }
        }

        return sb.ToString();
    }

Quelle est la manière la plus efficace de le faire ? À quoi ressemblerait une expression régulière, et comment se compare-t-elle à la manipulation normale des chaînes de caractères ?

Les chaînes de caractères qui seront nettoyées seront plutôt courtes, généralement entre 10 et 30 caractères.

388voto

Guffa Points 308133

Pourquoi pensez-vous que votre méthode n'est pas efficace ? C'est en fait l'une des méthodes les plus efficaces que vous puissiez utiliser.

Vous devez bien sûr lire le caractère dans une variable locale ou utiliser un énumérateur pour réduire le nombre d'accès au tableau :

public static string RemoveSpecialCharacters(this string str) {
   StringBuilder sb = new StringBuilder();
   foreach (char c in str) {
      if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '.' || c == '_') {
         sb.Append(c);
      }
   }
   return sb.ToString();
}

L'efficacité d'une telle méthode réside dans son caractère évolutif. Le temps d'exécution sera relatif à la longueur de la chaîne. Il n'y a pas de mauvaise surprise si vous l'utilisez sur une grande chaîne.

Edita:
J'ai fait un test de performance rapide, en exécutant chaque fonction un million de fois avec une chaîne de 24 caractères. Voici les résultats :

Fonction originale : 54,5 ms.
Ma suggestion de changement : 47,1 ms.
Le mien avec le réglage de la capacité StringBuilder : 43,3 ms.
Expression régulière : 294,4 ms.

Edit 2 : J'ai ajouté la distinction entre A-Z et a-z dans le code ci-dessus. (J'ai réexécuté le test de performance, et il n'y a pas de différence notable).

Edit 3 :
J'ai testé la solution lookup+char[], et elle s'exécute en environ 13 ms.

Le prix à payer est, bien sûr, l'initialisation de l'énorme table de consultation et son maintien en mémoire. Bon, ce n'est pas tant de données que ça, mais c'est beaucoup pour une fonction aussi triviale...

private static bool[] _lookup;

static Program() {
   _lookup = new bool[65536];
   for (char c = '0'; c <= '9'; c++) _lookup[c] = true;
   for (char c = 'A'; c <= 'Z'; c++) _lookup[c] = true;
   for (char c = 'a'; c <= 'z'; c++) _lookup[c] = true;
   _lookup['.'] = true;
   _lookup['_'] = true;
}

public static string RemoveSpecialCharacters(string str) {
   char[] buffer = new char[str.Length];
   int index = 0;
   foreach (char c in str) {
      if (_lookup[c]) {
         buffer[index] = c;
         index++;
      }
   }
   return new string(buffer, 0, index);
}

237voto

Blixt Points 23266

À moins que vous n'ayez vraiment besoin de tirer le maximum de votre fonction, choisissez ce qui est le plus facile à maintenir et à comprendre. Une expression régulière ressemblerait à ceci :

Pour plus de performances, vous pouvez soit le précompiler, soit lui demander de le compiler au premier appel (les appels suivants seront plus rapides).

public static string RemoveSpecialCharacters(string str)
{
    return Regex.Replace(str, "[^a-zA-Z0-9_.]+", "", RegexOptions.Compiled);
}

19voto

CMS Points 315406

Une expression régulière ressemblera à :

public string RemoveSpecialChars(string input)
{
    return Regex.Replace(input, @"[^0-9a-zA-Z\._]", string.Empty);
}

Mais si les performances sont très importantes, je vous recommande d'effectuer quelques tests de référence avant de sélectionner le "chemin regex"...

15voto

Steven Sudit Points 13793

Je suggère de créer une simple table de consultation, que vous pouvez initialiser dans le constructeur statique pour définir n'importe quelle combinaison de caractères comme étant valide. Cela vous permet d'effectuer une vérification rapide et unique.

modifier

De plus, pour plus de rapidité, vous voudrez initialiser la capacité de votre StringBuilder à la longueur de votre chaîne d'entrée. Cela évitera les réallocations. Ces deux méthodes combinées vous donneront à la fois vitesse et flexibilité.

autre montage

Je pense que le compilateur pourrait l'optimiser, mais pour des raisons de style et d'efficacité, je recommande d'utiliser foreach au lieu de for.

15voto

LukeH Points 110965
public static string RemoveSpecialCharacters(string str)
{
    char[] buffer = new char[str.Length];
    int idx = 0;

    foreach (char c in str)
    {
        if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z')
            || (c >= 'a' && c <= 'z') || (c == '.') || (c == '_'))
        {
            buffer[idx] = c;
            idx++;
        }
    }

    return new string(buffer, 0, idx);
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X