2012-12-10 81 views
2

我正在編寫自定義字符串拆分。它將在一個點(.)之前進行分割,前面沒有奇數個反斜槓(\)。快速自定義字符串拆分

«string» -> «IEnemerable<string>» 
"hello.world" -> "hello", "world" 
"abc\.123" -> "abc\.123" 
"aoeui\\.dhtns" -> "aoeui\\","dhtns" 

我想知道是否有將重新使用原來的字符串(速度)的子串,或者是有一個現有的拆分可以做這件事快?


這是我有,但比input.Split('.') //其中輸入字符串慢2-3倍。 (我知道這是一個(稍微複雜的問題,但不是很多)

public IEnumerable<string> HandMadeSplit(string input) 
    { 
     var Result = new LinkedList<string>(); 
     var word = new StringBuilder(); 
     foreach (var ch in input) 
     { 
      if (ch == '.') 
      { 
       Result.AddLast(word.ToString()); 
       word.Length = 0; 
      } 
      else 
      { 
       word.Append(ch); 
      } 
     } 
     Result.AddLast(word.ToString()); 
     return Result; 
    } 

它現在使用列表,而不是LinkedList的,並記錄開始,字符串的結束,並使用string.substring創建新的字符串。這確實很多,幾乎是一樣快string.split但我已經加入我的調整。(將添加代碼)

+1

「如果有,將重新使用原來的字符串(速度)的子串」 - 你不能真正實現這一點,如果它不是如何.NET將已表現。 – millimoose

+1

你是否會進入這種情況:'aeiou \ .bcde \\。opz'?或者你只會有一個'。'在你的字符串? – Jastill

+0

多個點(分隔符),偶爾還有逃脫的點\。 (非分隔符)。有時\ \以及。 –

回答

2

如果您需要性能,則顯示的循環是正確的方法。 (正則表達式不會是)。

切換到基於索引的for-loop。記住比賽開始的索引。不要追加個別字符。相反,請記住要複製的字符範圍,並通過每個項目的單個Substring調用執行此操作。另外,請不要使用LinkedList。幾乎所有病例除了隨機存取突變之外,它都比List慢。

你也可以從List切換到一個正常的數組,你用Array.Resize調整大小。這會導致代碼稍微繁瑣(因爲您已將方法中的List類的一部分內聯),但會削減一些小的開銷。

接下來,不要返回IEnumerable,因爲這會在訪問其項目時強制調用方通過間接方向。返回List或數組。

+0

更改爲列表,這有點,但也加快了客戶端(調用者)很多。 –

+1

+1感謝這些想法有所幫助 –

1

你不應該嘗試使用string.Split了點。

如果您需要有助於實現它,解決這個問題的一個簡單方法就是擁有循環罐頭字符串,跟蹤你找到一個合格點的最後一個地方。當你找到一個新的合格點(或者到達輸入字符串的末尾)時,只需要yield return這個當前的子字符串。

編輯:有關返回列表或數組對你的應用程序中使用產量

如果,最重要的事情是由主叫方迭代子花的時間,那麼你應該填充列表或數組並返回,如接受的問題中所建議的那樣。在收集子字符串時,我不會使用可調整大小的數組,因爲這會很慢。另一方面,如果您關心整體性能和內存,並且有時調用者不必遍歷整個列表,則應該使用yield return。當您使用yield return時,您的優勢是,在調用者呼叫MoveNext(直接或間接通過foreach)之前,根本沒有任何代碼正在執行。這意味着您可以節省分配數組/列表的內存,並節省分配/調整大小/填充列表所花費的時間。您幾乎只會花時間尋找子字符串的邏輯,並且這將會延遲,即 - 只有在實際需要時纔會執行,因爲調用方繼續迭代子字符串。

+0

做到了,但我需要它快。 –

+0

@richard:在string.Split()下面會隨着開銷循環。自己做這個想法會消除這些開銷並使其更快。 – Ian

+0

+1感謝,其中一些想法幫助 –

2

這是我最終解決的問題。它並不像string.split那樣快,但足夠好並且可以修改,做我想要的。

private IEnumerable<string> HandMadeSplit2b(string input) 
    { 
     //this one is margenaly better that the second best 2, but makes the resolver (its client much faster), nealy as fast as original. 
     var Result = new List<string>(); 
     var begining = 0; 
     var len = input.Length; 
     for (var index=0;index<len;index++) 
     { 
      if (input[index] == '.') 
      { 
       Result.Add(input.Substring(begining,index-begining)); 
       begining = index+1; 
      } 
     } 
     Result.Add(input.Substring(begining)); 
     return Result; 
    }