2012-07-09 93 views
18

我使用这种方法来清理字符串清理字符串?有没有更好的方法来做到这一点?

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

任何建议,将不胜感激。

+1

的目的是什么,你'“清洗”'一个字符串? – 2012-07-09 13:14:40

+0

我基本上处理了很多Qurystring值... – 2012-07-09 13:15:23

+0

你只是想让一个字符串null或什么? – akhil 2012-07-09 13:15:35

回答

33

OK,请考虑以下测试:

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\[email protected]]", ""); 
    } 

    // 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<char>(" ?&^$#@!()+-,:;<>’\'-_*"); 
     // 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<char> removeChars = new HashSet<char>(" ?&^$#@!()+-,:;<>’\'-_*"); 
     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 L.B 
    public static string UseWhere(string dirtyString) 
    { 
     return new String(dirtyString.Where(Char.IsLetterOrDigit).ToArray()); 
    } 
} 

static class Program 
{ 
    /// <summary> 
    /// The main entry point for the application. 
    /// </summary> 
    [STAThread] 
    static void Main() 
    { 
     var dirtyString = "sdfdf.dsf8908()=(=([email protected]€sdöf////fj()=/§(§&/(\"&sdfdf.dsf8908()=(=([email protected]€sdöf////fj()=/§(§&/(\"&sdfdf.dsf8908()=(=([email protected]€sdöf"; 
     var sw = new Stopwatch(); 

     var iterations = 50000; 

     sw.Start(); 
     for (var i = 0; i < iterations; i++) 
      CleanString.<SomeMethod>(dirtyString); 
     sw.Stop(); 
     Debug.WriteLine("CleanString.<SomeMethod>: " + sw.ElapsedMilliseconds.ToString()); 
     sw.Reset(); 

     .... 
     <repeat> 
     ....  
    } 
} 

输出

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

结论

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

当连续调用50000(!)次时,禁食(UseWhere:233ms)和最慢(UseStringBuilder:2805ms)方法之间的时间差异为2572ms。如果不经常运行该方法,您应该不需要关心它。

但是,如果你这样做,使用UseWhere方法(书面由L.B);但也要注意它略有不同。

+0

+1不错的完整答案 - 我喜欢它:] – MoonKnight 2012-07-09 13:50:22

+0

这会给'返回新的字符串(dirtyString。 Where(Char.IsLetterOrDigit).ToArray())'在你的机器上? – 2012-07-09 14:29:29

+0

速度很快。 50000次迭代:182ms(下一个是'UseStringBuilderWithHashSet2',具有266ms) – sloth 2012-07-09 15:03:59

3

与空字符串

4

如果是纯粹的速度和效率你以后,我会建议做这样的事情:

public static string CleanString(string dirtyString) 
{ 
    HashSet<char> removeChars = new HashSet<char>(" ?&^$#@!()+-,:;<>’\'-_*"); 
    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)。这将减少内存使用并提高速度,特别是在较长的字符串上。

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

+0

这个对我来说很好看.. – 2012-07-09 13:34:01

+0

'removeChars.IndexOf'是'O(n)'操作。一个'HashSet'会更好。 – 2012-07-09 13:40:11

+0

@ L.B感谢您的建议。我更新了我的示例代码。 – 2012-07-09 13:47:15

2

我不知道,使用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(); 
    } 
} 
+0

这无疑有助于使用StringBuilder类 – 2012-07-09 13:34:52

+0

'removeChars.Contains开辟了一个新的想法对我来说'是'O(n)','HashSet'会更好。 – 2012-07-09 13:38:40

1

也许它有助于首先解释了“为什么”,然后是“什么”。性能降低的原因是因为c#复制并替换每个替换的字符串。从我在使用正则表达式的经验。NET并不总是更好 - 尽管在大多数情况下(我认为包括这个),它可能会工作得很好。

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

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

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

BTW:当你要处理高代理Unicode字符该解决方案是不正确 - 但可以很容易地适用于包括这些字符。

-Stefan。

1

这个更快!
使用:

string [email protected]"[email protected]$%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(); 
    } 
0

我不能把时间花在酸测试这一点,但根据需要这一行居然没有干净的斜线。

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

我不得不单独添加斜线和转义反斜线

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