VB.NET中字符串中的字符替换

时间:2010-11-30 22:08:43

标签: vb.net string character-replacement

我可以多快地替换字符串中的字符?

因此,这个问题的背景是:我们有几个应用程序通过套接字相互通信并与客户端的应用程序通信。这些套接字消息包含不可打印的字符(例如chr(0)),需要用预定的字符串替换(例如“{Nul}”},因为套接字消息保存在日志文件中。每条日志消息都需要替换字符。

现在我开始阅读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。

所以我的问题是:我可以加快速度吗?我错过了什么?

5 个答案:

答案 0 :(得分:1)

您可以通过减少一些查找来挤出更快的速度。以此为例:

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

.Contains方法是O(n)。在最坏的情况下,你将遍历整个字符串中的所有字符而不查找任何字符,因此您希望对数组中的每个字符至少遍历一次,因此其O(nm)其中n是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)。

答案 1 :(得分:0)

StringBuilder提供了.NET中最快的Replace()函数。

答案 2 :(得分:0)

这里有几点一般性说明:

  1. 您可以使用简单的.IndexOf().Contains()搜索来改进搜索功能,因为您只需查找单个字符。
  2. 您可以通过直接从函数返回StringBuilder对象并为其他函数提供重载来提高总吞吐量,这些函数接受stringbuilders作为输入或稍后在某个过程中调用.ToString()(注意:您也可以在已经是字符串的对象上调用.ToString())
  3. 你应该能够通过在链上进一步使用StringReader / TextReader来进一步提高性能/吞吐量,并继续将所有内容视为不断传递给链的流。
  4. 至少你可以用这种方式修改你的最终方法:

    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
    

    请注意,您的基准测试将在很大程度上取决于您投射的字符串的类型,因此请确保您使用最具代表性的样本(并且它应该是一个大小合适的样本)。

答案 3 :(得分:0)

看看这个example。它有一些比较这两种方法的基准统计数据。

答案 4 :(得分: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