清理字符串? 有没有更好的方法呢?

我正在使用此方法来清理字符串

public static string CleanString(string dirtyString) { string removeChars = " ?&^$#@!()+-,:;'\'-_*"; string result = dirtyString; foreach (char c in removeChars) { result = result.Replace(c.ToString(), string.Empty); } return result; } 

这种方法工作正常。但是这种方法存在性能故障。 每次我传递字符串时,每个字符都进入循环,如果我有一个大字符串,那么返回该对象将花费太多时间。

有没有其他更好的方法做同样的事情? 比如在LINQ或JQUERY / Javascript中

任何建议将不胜感激。

好的,请考虑以下测试:

 public class CleanString { //by MSDN http://msdn.microsoft.com/en-us/library/844skk0h(v=vs.71).aspx public static string UseRegex(string strIn) { // Replace invalid characters with empty strings. return Regex.Replace(strIn, @"[^\w\.@-]", ""); } // by Paolo Tedesco public static String UseStringBuilder(string strIn) { const string removeChars = " ?&^$#@!()+-,:;<>'\'-_*"; // specify capacity of StringBuilder to avoid resizing StringBuilder sb = new StringBuilder(strIn.Length); foreach (char x in strIn.Where(c => !removeChars.Contains(c))) { sb.Append(x); } return sb.ToString(); } // by Paolo Tedesco, but using a HashSet public static String UseStringBuilderWithHashSet(string strIn) { var hashSet = new HashSet(" ?&^$#@!()+-,:;<>'\'-_*"); // specify capacity of StringBuilder to avoid resizing StringBuilder sb = new StringBuilder(strIn.Length); foreach (char x in strIn.Where(c => !hashSet.Contains(c))) { sb.Append(x); } return sb.ToString(); } // by SteveDog public static string UseStringBuilderWithHashSet2(string dirtyString) { HashSet removeChars = new HashSet(" ?&^$#@!()+-,:;<>'\'-_*"); StringBuilder result = new StringBuilder(dirtyString.Length); foreach (char c in dirtyString) if (removeChars.Contains(c)) result.Append(c); return result.ToString(); } // original by patel.milanb public static string UseReplace(string dirtyString) { string removeChars = " ?&^$#@!()+-,:;<>'\'-_*"; string result = dirtyString; foreach (char c in removeChars) { result = result.Replace(c.ToString(), string.Empty); } return result; } // by LB public static string UseWhere(string dirtyString) { return new String(dirtyString.Where(Char.IsLetterOrDigit).ToArray()); } } static class Program { ///  /// The main entry point for the application. ///  [STAThread] static void Main() { var dirtyString = "sdfdf.dsf8908()=(=(sadfJJLef@ssyd€sdöf////fj()=/§(§&/(\"&sdfdf.dsf8908()=(=(sadfJJLef@ssyd€sdöf////fj()=/§(§&/(\"&sdfdf.dsf8908()=(=(sadfJJLef@ssyd€sdöf"; var sw = new Stopwatch(); var iterations = 50000; sw.Start(); for (var i = 0; i < iterations; i++) CleanString.(dirtyString); sw.Stop(); Debug.WriteLine("CleanString.: " + sw.ElapsedMilliseconds.ToString()); sw.Reset(); ....  .... } } 

产量

 CleanString.UseReplace: 791 CleanString.UseStringBuilder: 2805 CleanString.UseStringBuilderWithHashSet: 521 CleanString.UseStringBuilderWithHashSet2: 331 CleanString.UseRegex: 1700 CleanString.UseWhere: 233 

结论

您使用哪种方法可能无关紧要。

UseWhereUseWhere :233ms)和最慢( UseStringBuilder :2805ms)方法之间的时间差是连续调用50000(!)次时的2572ms。 如果不经常运行该方法,您可能不需要关心它。

但是如果你这样做,请使用UseWhere方法(由LB编写); 但也要注意它略有不同。

如果它纯粹是你所追求的速度和效率,我建议做这样的事情:

 public static string CleanString(string dirtyString) { HashSet removeChars = new HashSet(" ?&^$#@!()+-,:;<>'\'-_*"); StringBuilder result = new StringBuilder(dirtyString.Length); foreach (char c in dirtyString) if (!removeChars.Contains(c)) // prevent dirty chars result.Append(c); return result.ToString(); } 

RegEx当然是一个优雅的解决方案,但它增加了额外的开销。 通过指定字符串构建器的起始长度,它只需要分配一次内存(并且最后一次分配ToString )。 这将减少内存使用量并提高速度,尤其是在较长的字符串上。

但是,正如LB所说,如果你使用它来正确编码绑定到HTML输出的文本,你应该使用HttpUtility.HtmlEncode而不是自己动手。

使用正则表达式[?&^$#@!()+-,:;<>'\'-_*]替换为空字符串

我不知道在性能方面,使用Regex或LINQ是否会有所改进。
可能有用的东西是使用StringBuilder创建新字符串,而不是每次使用string.Replace

 using System.Linq; using System.Text; static class Program { static void Main(string[] args) { const string removeChars = " ?&^$#@!()+-,:;<>'\'-_*"; string result = "x&y(z)"; // specify capacity of StringBuilder to avoid resizing StringBuilder sb = new StringBuilder(result.Length); foreach (char x in result.Where(c => !removeChars.Contains(c))) { sb.Append(x); } result = sb.ToString(); } } 

尝试一下: http : //msdn.microsoft.com/en-us/library/xwewhkd1.aspx

也许首先解释’为什么’然后再解释’什么’是有帮助的。 您的性能降低的原因是因为c#copies-and -‘s替换每个替换的字符串。 根据我在.NET中使用Regex的经验并不总是更好 – 虽然在大多数情况下(我认为包括这个)它可能会工作得很好。

如果我真的需要性能,我通常不会让运气好,只需告诉编译器我想要的是什么:即:创建一个带有上限字符数的字符串并复制你需要的所有字符。 也可以用开关/ case或数组替换hashset,在这种情况下你最终可能会跳转表或数组查找 – 这甚至更快。

“务实”的最佳但快速的解决方案是:

 char[] data = new char[dirtyString.Length]; int ptr = 0; HashSet hs = new HashSet() { /* all your excluded chars go here */ }; foreach (char c in dirtyString) if (!hs.Contains(c)) data[ptr++] = c; return new string(data, 0, ptr); 

顺便说一句:当您想要处理高代理Unicode字符时,此解决方案不正确 – 但可以轻松调整以包含这些字符。

-Stefan。

这个更快!
使用:

 string dirty=@"tfgtf$@$%gttg%$% 664%$"; string clean = dirty.Clean(); public static string Clean(this String name) { var namearray = new Char[name.Length]; var newIndex = 0; for (var index = 0; index < namearray.Length; index++) { var letter = (Int32)name[index]; if (!((letter > 96 && letter < 123) || (letter > 64 && letter < 91) || (letter > 47 && letter < 58))) continue; namearray[newIndex] = (Char)letter; ++newIndex; } return new String(namearray).TrimEnd(); } 

我无法在酸性测试上花费时间,但这条线实际上并没有按照需要清理斜线。

 HashSet removeChars = new HashSet(" ?&^$#@!()+-,:;<>'\'-_*"); 

我不得不单独添加斜杠并逃避反斜杠

 HashSet removeChars = new HashSet(" ?&^$#@!()+-,:;<>''-_*"); removeChars.Add('/'); removeChars.Add('\\');