C #: Suppression des caractères non valides courants d’une chaîne: améliorer cet algorithme

Considérez la nécessité de supprimer les caractères non valides d’une chaîne. Les caractères doivent simplement être supprimés et remplacés par un blanc ou une ssortingng.Empty .

 char[] BAD_CHARS = new char[] { '!', '@', '#', '$', '%', '_' }; //simple example foreach (char bad in BAD_CHARS) { if (someSsortingng.Contains(bad)) someSsortingng = someSsortingng.Replace(bad.ToSsortingng(), ssortingng.Empty); } 

J’aurais vraiment aimé faire ça:

 if (BAD_CHARS.Any(bc => someSsortingng.Contains(bc))) someSsortingng.Replace(bc,ssortingng.Empty); // bc is out of scope 

Question: Avez-vous des suggestions sur la refactorisation de cet algorithme, ou des algorithmes plus simples, plus faciles à lire, performants et maintenables?

 char[] BAD_CHARS = new char[] { '!', '@', '#', '$', '%', '_' }; //simple example someSsortingng = ssortingng.Concat(someSsortingng.Split(BAD_CHARS,SsortingngSplitOptions.RemoveEmptyEnsortinges)); 

devrait faire l’affaire (désolé pour les erreurs de syntaxe plus petites, je suis sur mon téléphone)

Je ne sais pas si elle est lisible, mais une expression régulière pourrait faire ce dont vous avez besoin pour:

 someSsortingng = Regex.Replace(someSsortingng, @"[!@#$%_]", ""); 

La classe de ssortingng est immuable (bien qu’un type de référence), toutes ses méthodes statiques sont donc conçues pour renvoyer une nouvelle variable de ssortingng . Appeler someSsortingng.Replace sans l’affecter à quoi que ce soit n’aura aucun effet sur votre programme. – On dirait que vous avez résolu ce problème.

Le principal problème de votre algorithme suggéré est qu’il assigne de manière répétée de nombreuses nouvelles variables de ssortingng , ce qui peut entraîner de lourdes pertes de performances. LINQ n’aide pas vraiment les choses ici. (Je ne rends pas le code beaucoup plus court et certainement pas plus lisible, à mon avis.)

Essayez la méthode d’extension suivante. La clé est l’utilisation de SsortingngBuilder , ce qui signifie qu’un seul bloc de mémoire est affecté au résultat lors de l’exécution.

 private static readonly HashSet badChars = new HashSet { '!', '@', '#', '$', '%', '_' }; public static ssortingng CleanSsortingng(this ssortingng str) { var result = new SsortingngBuilder(str.Length); for (int i = 0; i < str.Length; i++) { if (!badChars.Contains(str[i])) result.Append(str[i]); } return result.ToString(); } 

Cet algorithme utilise également la classe .NET 3.5 'HashSet' pour donner à O(1) le temps de recherche nécessaire à la détection d'un caractère incorrect. Cela rend l’algorithme général O(n) plutôt que O(nm) de celui que vous avez posté ( m étant le nombre de caractères incorrects); Comme expliqué ci-dessus, l'utilisation de la mémoire est également meilleure.

Celui-ci est plus rapide que HashSet . De plus, si vous devez effectuer cette action souvent, veuillez considérer les fondements de la question que j’ai posée ici .

 private static readonly bool[] BadCharValues; static StaticConstructor() { BadCharValues = new bool[char.MaxValue+1]; char[] badChars = { '!', '@', '#', '$', '%', '_' }; foreach (char c in badChars) BadCharValues[c] = true; } public static ssortingng CleanSsortingng(ssortingng str) { var result = new SsortingngBuilder(str.Length); for (int i = 0; i < str.Length; i++) { if (!BadCharValues[str[i]]) result.Append(str[i]); } return result.ToString(); } 

Quelque chose à considérer – si c’est pour les mots de passe (par exemple), vous voulez rechercher et conserver les bons caractères , et présumer que tout le rest est mauvais. Il est plus facile de filtrer correctement ou de bonnes choses, puis d’essayer de deviner toutes les mauvaises choses.

Pour chaque caractère si le caractère est bon -> Conservez-le (copie dans le tampon, peu importe.)

Jeff

si vous voulez toujours le faire de manière LINQy:

 public static ssortingng CleanUp(this ssortingng orig) { var badchars = new List() { '!', '@', '#', '$', '%', '_' }; return new ssortingng(orig.ToCharArray().Where(c => !badchars.Contains(c)).ToArray()); } 

Pourquoi auriez-vous VRAIMENT AIME faire cela? Le code n’est absolument pas simple, vous forcez simplement une méthode d’extension de requête dans votre code.

En passant, le contrôle Contains semble redondant, tant du sharepoint vue conceptuel que du sharepoint vue des performances. Contains toute façon, le Replace(bad.ToSsortingng(), ssortingng.Empty) doit parcourir toute la chaîne, vous pouvez également appeler Replace(bad.ToSsortingng(), ssortingng.Empty) pour chaque caractère et oublier s’il est réellement présent ou non.

Bien entendu, une expression régulière est toujours une option et peut être plus performante (si pas moins claire) dans une situation comme celle-ci.

Conseil supplémentaire: Si vous ne souhaitez pas vous souvenir du tableau de caractères non valide pour les fichiers, vous pouvez utiliser Path.GetInvalidFileNameChars() . Si vous le vouliez pour les chemins, c’est Path.GetInvalidPathChars

 private static ssortingng RemoveInvalidChars(ssortingng str) { return ssortingng.Concat(str.Split(Path.GetInvalidFileNameChars(), SsortingngSplitOptions.RemoveEmptyEnsortinges)); } 

C’est plutôt propre. Le limite aux caractères valides au lieu de supprimer ceux qui ne sont pas valides. Vous devriez probablement le scinder en constantes:

 ssortingng clean = new ssortingng(@"Sour!ce Str&*(@ing".Where(c => @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ,.".Contains(c)).ToArray()