2010-11-30 54 views
5

我可以用字符串替換字符的速度有多快?VB.NET中字符串的替換

所以這個問題的背景是這樣的:我們有幾個應用程序通過套接字與客戶的應用程序進行通信。這些套接字消息包含需要用預定字符串(例如「{Nul}」}替換的非可打印字符(例如,chr(0)),因爲套接字消息保存在日誌文件中。每個日誌消息將需要有替換的字符。

現在,我開始對這個小小的冒險指數從this MSDN link這是我從不同的崗位從這個網站上發現。

我們當前使用的方法......在一天的開始...正在使用StringBuilder檢查所有可能的替換,例如...

Public Function ReplaceSB(ByVal p_Message As String) As String 
     Dim sb As New System.Text.StringBuilder(p_Message) 

     sb.Replace(Chr(0), "{NUL}") 
     sb.Replace(Chr(1), "{SOH}") 

     Return sb.ToString 
    End Function 

現在,當博客文章指出將StringBuilder退出並使用string.replace確實會產生更快的結果。 (實際上,使用StringBuilder的是整天這樣做的最慢的方法。)

p_Message = p_Message.Replace(Chr(0), "{NUL}") 
    p_Message = p_Message.Replace(Chr(1), "{SOH}") 

知道,不是每一個消息都需要經過這個過程中,我認爲它會節省時間,不必處理這些消息是可以被排除在外。所以使用正則表達式我首先搜索字符串,然後確定是否需要處理。這與使用string.replace大致相同,基本上是節省了不處理所有字符串的時間,但是由於使用正則表達式檢查所有字符串而浪費時間。

然後有人建議嘗試使用一些數組,它們的索引與舊的和新的匹配,並用它來處理消息。所以它會是這樣的...

Private chrArray() As Char = {Chr(0), Chr(1)} 
Private strArray() As String = {"{NUL}", "{SOH}"} 

Public Function TestReplace(ByVal p_Message As String) As String 
    Dim i As Integer 

    For i = 0 To ((chrArray.Length) - 1) 
     If p_Message.Contains(chrArray(i).ToString) Then 
      p_Message = p_Message.Replace(chrArray(i), strArray(i)) 
     End If 
    Next 

    Return p_Message 
End Function 

這是迄今爲止我發現處理這些消息的最快方式。我已經嘗試了各種其他方式來解決這個問題,比如將傳入的字符串轉換爲字符數組,並且同時嘗試通過字符串而不是chrArray進行循環。

所以我的問題是:我可以做得更快嗎?我錯過了什麼?

+0

如果你必須使用C#的選項,你也許可以寫出不安全的代碼,一個不懷好意的快捷功能。 – Juliet 2010-11-30 22:41:17

+0

我曾想知道這是否可能,但很快就將這個選項計算出來了,因爲我得到的參數與它們一起工作......哦, – Tim 2010-12-01 03:07:05

回答

1

您可以通過減少一些查找來獲得更多的速度。舉例如下:

If p_Message.Contains(chrArray(i).ToString) Then 

.Contains方法是O(n)。在最糟糕的情況下,你會遍歷整個字符串中的所有字符而沒有發現任何東西,所以你期望至少遍歷數組中每個字符的一次,所以它的O(nm)其中n是你的字符串和m是你正在替換的字符數。

你可能會得到一個更好一點的表現做了如下(我的VB-FU是生鏽的,尚未經過測試;)):

Private Function WriteToCharList(s as String, dest as List(Of Char)) 
    for each c as Char in s 
     dest.Add(c) 
    Next 
End Function 

Public Function TestReplace(ByVal p_Message As String) As String 
    Dim chars as new List(Of Char)(p_Message.Length) 

    For each c as Char in p_Message 
     Select Case c 
      Case Chr(0): WriteToCharList("{NUL}", chars) 
      Case Chr(1): WriteToCharList("{SOH}", chars) 
      Case Else: chars.Add(c); 
     End Select 
    Next 

    Return New String(chars) 
End Function 

這將在p_Message遍歷字符最多兩次(一次遍歷,一次當字符串構造函數複製char數組時),使這個函數成爲O(n)。

0

StringBuilder在.NET中提供最快的Replace()函數。

+0

StringBuilder的replace()函數是我整天試過的最慢的函數。當通過240條日誌消息進行處理時,StringBuilder比處理來自我的OP的消息的最後一個方式慢1.8毫秒。 – Tim 2010-11-30 22:20:40

+0

「這取決於」在這裏是正確的答案。如果沒有真正的性能分析,你無法真正保證StringBuilder的速度更快。 – Juliet 2010-11-30 22:22:22

0

一對夫婦在這裏一般注意事項:

  1. 您可能能夠通過使用普通的.IndexOf().Contains()搜索,以改善搜索功能,因爲你只是尋找單個字符。
  2. 您可以通過直接從函數返回StringBuilder對象併爲其他接受字符串構建器作爲輸入或調用.ToString()稍後處理的函數提供重載,從而提高總吞吐量(注意:您也可以在已經是字符串的對象上調用.ToString())
  3. 您應該一定能夠通過在鏈的更上方使用StringReader/TextReader來進一步提高性能/吞吐量,並繼續將所有內容視爲不斷流入鏈中的流。

在最起碼你可以修改你的最後一個方法是這樣的:

Public Function TestReplace(ByVal p_Message As String) As String 
    Static chrArray() As Char = {ChrW(0), ChrW(1)} 
    Static strArray() As String = {"{NUL}", "{SOH}"} 

    Dim rdr As New StringReader(p_Message) 
    Dim result As New StringWriter() 

    Dim i As Integer 
    While (i = rdr.Read()) <> -1 
     Dim c As Char = ChrW(i) 
     Dim index As Integer = Array.IndexOf(chrArray, c) 
     If index >= 0 Then result.Write(strArray(index)) Else result.Write(c) 
    End While 

    Return result.ToString() 
End Function 

請注意,您的基準,將在很大程度上取決於那種你在它扔串的,所以一定要確保你使用最有代表性的樣本(它應該是一個好大小的樣本)是可能的。

+0

我用不同的方式使用.IndexOf()和.Contains()而沒有獲得任何結果,通常大約慢一到兩毫秒。我將嘗試使用您的編號2和3進行更多測試...我將回傳結果 – Tim 2010-11-30 22:29:19

+0

@Tim - 請參閱我的更新回答 – 2010-11-30 22:33:34

0

看看這個example。它有一些比較兩種方法的基準統計數據。

0

這也應該更快:

Private Shared strList As New Dictionary(Of Char, String) 

    Shared Sub New() 
     strList.Add(Chr(0), "{NUL}") 
     strList.Add(Chr(1), "{SOH}") 
    End Sub 

    Public Function TestReplace(ByVal p_Message As String) As String 
     For Each c As Char In strList.Keys 
      If p_Message.IndexOf(c) <> -1 Then 
       p_Message = p_Message.Replace(c, strList(c)) 
      End If 
     Next 

     Return p_Message 
    End Function