C#:从字符串中删除常见的无效字符:改进此算法

考虑从字符串中删除无效字符的要求。 只需要删除字符并替换为blank或string.Empty

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

真的很喜欢这样做:

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

问题:您对重构此算法或任何更简单,易于阅读,高性能,可维护的算法有什么建议吗?

 char[] BAD_CHARS = new char[] { '!', '@', '#', '$', '%', '_' }; //simple example someString = string.Concat(someString.Split(BAD_CHARS,StringSplitOptions.RemoveEmptyEntries)); 

应该做的伎俩(抱歉我的手机上有任何较小的语法错误)

我不知道它的可读性,但正则表达式可以满足您的需要:

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

string类是不可变的(尽管是引用类型),因此它的所有静态方法都被设计为返回一个新的 string变量。 调用someString.Replace而不将其分配给任何东西将不会对您的程序产生任何影响。 – 好像你解决了这个问题。

您建议的算法的主要问题是它重复分配许多新的string变量,可能会导致性能大幅下降。 LINQ在这里并没有真正的帮助。 (在我看来,我不会使代码明显缩短,当然也不会更具可读性。)

请尝试以下扩展方法。 关键是使用StringBuilder ,这意味着在执行期间只为结果分配了一个内存块。

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

该算法还利用.NET 3.5'HashSet'类为O(1)查找检测错误char的查找时间。 这使得整体算法O(n)而不是您发布的算法的O(nm)m是坏字符的数量); 如上所述,内存使用情况也好得多。

这个比HashSet快。 此外,如果您必须经常执行此操作,请考虑我在此处提出的此问题的基础。

 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 string CleanString(string str) { var result = new StringBuilder(str.Length); for (int i = 0; i < str.Length; i++) { if (!BadCharValues[str[i]]) result.Append(str[i]); } return result.ToString(); } 

需要考虑的事项 – 如果这是用于密码(比如说),你想要扫描并保留好的角色 ,并假设其他一切都不好。 它更容易正确过滤或好事,然后尝试猜测所有坏事。

对于每个字符如果字符是好的 – >保留它(复制到输出缓冲区,无论如何。)

杰夫

如果您仍想以LINQy方式执行此操作:

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

你为什么真的喜欢这样做? 代码绝对不简单,你只是强迫查询扩展方法进入你的代码。

另外, Contains检查在概念上和从性能角度看都是多余的。 无论如何, Contains必须贯穿整个字符串,你也可以为每个字符调用Replace(bad.ToString(), string.Empty)并忘记它是否真正存在。

当然,正则表达式总是一种选择,并且在这种情况下可能更具性能(如果不是更不清楚)。

额外提示:如果您不想记住对文件无效的char数组,可以使用Path.GetInvalidFileNameChars() 。 如果你想要Paths,那就是Path.GetInvalidPathChars

 private static string RemoveInvalidChars(string str) { return string.Concat(str.Split(Path.GetInvalidFileNameChars(), StringSplitOptions.RemoveEmptyEntries)); } 

这很干净。 将其限制为有效字符,而不是删除无效字符。 您可能应该将其拆分为常量:

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