2009-08-24 41 views
56

是否有這樣做的更好的辦法...在C#替換多個字符串元素

MyString.Trim().Replace("&", "and").Replace(",", "").Replace(" ", " ") 
     .Replace(" ", "-").Replace("'", "").Replace("/", "").ToLower(); 

我已經擴展了串類,以保持它歸結爲一個工作,但有一個更快的方法?

public static class StringExtension 
{ 
    public static string clean(this string s) 
    { 
     return s.Replace("&", "and").Replace(",", "").Replace(" ", " ") 
       .Replace(" ", "-").Replace("'", "").Replace(".", "") 
       .Replace("eacute;", "é").ToLower(); 
    } 
} 

只是爲了好玩(和停止在評論參數) 我猛的一要點了標杆下面的各種例子。

https://gist.github.com/ChrisMcKee/5937656

可怕的正則表達式選項得分;字典選項出現最快; stringbuilder替換的冗長版本比短手稍快。

+0

基於你在你的基準是什麼樣子的字典版本沒有拼盡全力,我懷疑是替代的是什麼使得它比快StringBuilder解決方案。 – toad 2014-09-12 21:23:34

+1

@toad您好,從2009年起;我在四月份就下面這個明顯的錯誤添加了一條評論。雖然我跳過了D,但它的要點已經更新。字典版本仍然更快。 – 2014-09-15 00:24:04

+0

可能重複的[替代字符串。多次更換?](http://stackoverflow.com/questions/12007358/alternative-to-string-replace-multiple-times) – 2016-03-17 20:19:57

回答

79

更快 - 沒有。更有效 - 是的,如果您將使用StringBuilder類。通過實施,每項操作都會生成一個字符串副本,在某些情況下可能會影響性能。字符串是不可變的對象,所以每個操作只是返回一個修改後的副本。

如果您希望在多個Strings上主動調用這種方法,那麼將它的實現「遷移」到StringBuilder類可能會更好。通過它可以直接在該實例上進行任何修改,因此您可以省去不必要的複製操作。

public static class StringExtention 
{ 
    public static string clean(this string s) 
    { 
     StringBuilder sb = new StringBuilder (s); 

     sb.Replace("&", "and"); 
     sb.Replace(",", ""); 
     sb.Replace(" ", " "); 
     sb.Replace(" ", "-"); 
     sb.Replace("'", ""); 
     sb.Replace(".", ""); 
     sb.Replace("eacute;", "é"); 

     return sb.ToString().ToLower(); 
    } 
} 
+1

爲清晰起見,字典答案是最快的http://stackoverflow.com/a/1321366/52912 – 2013-07-06 20:28:18

+2

在你的基準https://gist.github.com/ChrisMcKee/5937656字典測試不完整:它不會做所有的替換,並且「」替代「」,而不是「」。不做所有替換可能是原因,爲什麼它在基準測試中速度最快。正則表達式替換也不完整。但最重要的是你的字符串TestData是_very_ short。就像接受的答案狀態一樣,字符串必須具有很大的長度才能使StringBuilder具有優勢。您能否重複10kB,100kB和1MB字符串的基準測試? – Leif 2014-02-14 08:42:48

+0

它是一個很好的觀點;因爲它被用來進行網址清理,因此100kb - 1mb的測試將是不現實的。我會更新基準,因此儘管它使用了整個事情,但這是一個錯誤。 – 2014-04-25 09:30:55

8

這將是更有效的:

public static class StringExtension 
{ 
    public static string clean(this string s) 
    { 
     return new StringBuilder(s) 
       .Replace("&", "and") 
       .Replace(",", "") 
       .Replace(" ", " ") 
       .Replace(" ", "-") 
       .Replace("'", "") 
       .Replace(".", "") 
       .Replace("eacute;", "é") 
       .ToString() 
       .ToLower(); 
    } 
} 
+0

真的很難閱讀。我確信你知道它做了什麼,但是初級開發人員會對實際上發生的事情撓頭。我同意 - 我也一直在尋找寫東西的短褲 - 但這只是爲了我自己的滿意。其他人在這堆亂七八糟的時候都嚇壞了。 – ppumkin 2013-02-12 10:55:05

+2

這實際上比較慢。 BenchmarkOverhead ... 13毫秒 StringClean-user151323 ... 2843ms StringClean-TheVillageIdiot ... 2921ms 而變化重播但得到的答覆勝 https://gist.github.com/anonymous/5937596 – 2013-07-05 22:16:00

10

也許有點更具可讀性?

public static class StringExtension { 

     private static Dictionary<string, string> _replacements = new Dictionary<string, string>(); 

     static StringExtension() { 
      _replacements["&"] = "and"; 
      _replacements[","] = ""; 
      _replacements[" "] = " "; 
      // etc... 
     } 

     public static string clean(this string s) { 
      foreach (string to_replace in _replacements.Keys) { 
       s = s.Replace(to_replace, _replacements[to_replace]); 
      } 
      return s; 
     } 
    } 

中增加新城裏的約StringBuilder的建議...

+4

這樣會更可讀性如下:'private static Dictionary _replacements = new Dictionary (){{「&」,「and」},{「,」,「」},{「」,「」 }/*等* /};' – ANeves 2011-08-04 10:04:10

+1

或當然... 私人靜態只讀字典<字符串,字符串>替換=新詞典<字符串,字符串>(){{ 「&」, 「和」},{ 「,」,「」},{「」,「」}/* etc * /}; \t \t公共靜態字符串清潔(這字符串s) \t \t { \t \t \t返回Replacements.Keys.Aggregate(S,(電流,toReplace)=> current.Replace(toReplace,更換[toReplace])); \t \t} – 2013-07-05 22:22:44

1

我在做類似的事情,但對我來說,我做的序列化/反序列化,所以我需要能夠去兩個方向。我發現使用一個字符串[] []與字典幾乎完全一樣,包括初始化,但是你也可以轉向另一個方向,將替換字符返回到它們的原始值,這是字典確實沒有設置的。

編輯:您可以使用Dictionary<Key,List<Values>>,以獲得相同的結果字符串[] []

4

如果你只是一個漂亮的解決方案後,並不需要保存幾納秒,如何對一些LINQ糖?

var input = "test1test2test3"; 
var replacements = new Dictionary<string, string> { { "1", "*" }, { "2", "_" }, { "3", "&" } }; 

var output = replacements.Aggregate(input, (current, replacement) => current.Replace(replacement.Key, replacement.Value)); 
+0

類似於Gist中的例子C(如果你在上面看一下,醜陋的linq語句在註釋中) – 2014-09-15 00:26:35

+1

有趣的是,你定義了一個函數表達式作爲「醜陋」而不是過程函數。 – TimS 2014-09-15 00:36:30

+0

不會爭論它;其僅僅是偏好。正如你所說,linq只是語法糖;正如我所說我已經把等效代碼:) – 2014-09-15 08:48:30

3

在建議的解決方案中可能會優化一件事。對Replace()進行多次調用會使代碼在同一個字符串上執行多次傳遞。由於CPU高速緩存容量未命中,因此解決方案可能會很長。可能是一個應該考慮replacing multiple strings in a single pass

-1
string input = "it's worth a lot of money, if you can find a buyer."; 
for (dynamic i = 0, repl = new string[,] { { "'", "''" }, { "money", "$" }, { "find", "locate" } }; i < repl.Length/2; i++) { 
    input = input.Replace(repl[i, 0], repl[i, 1]); 
} 
使用LINQ
+1

你應該考慮添加上下文到你的答案。就像是對它做了什麼的簡單解釋一樣,如果相關,爲什麼你按照你的方式編寫它。 – Neil 2017-03-16 00:31:40

1

另一種選擇是

[TestMethod] 
public void Test() 
{ 
    var input = "it's worth a lot of money, if you can find a buyer."; 
    var expected = "its worth a lot of money if you can find a buyer"; 
    var removeList = new string[] { ".", ",", "'" }; 
    var result = input; 

    removeList.ToList().ForEach(o => result = result.Replace(o, string.Empty)); 

    Assert.AreEqual(expected, result); 
} 
+0

你可以宣佈'無功removeList =新名單 {/*...*/};'然後就調用'removeList.ForEach(/*...*/);'和簡化代碼。還要注意,它並沒有完全回答這個問題,因爲* all * found字符串被替換爲'String.Empty'。 – 2017-11-17 22:17:39