2012-07-09 136 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('\\'); 
相關問題