6

文字列内の文字をどれくらい速く置き換えることができますか?

したがって、この質問の背景は次のとおりです。ソケットを介して相互に通信し、クライアントのアプリケーションと通信するアプリケーションがいくつかあります。これらのソケットメッセージには、印刷できない文字(chr(0)など)が含まれています。ソケットメッセージはログファイルに保存されるため、事前に定義された文字列( "{Nul}"}など)に置き換える必要があります。すべてのログメッセージでは、文字を置き換える必要があります。

今、私はこのサイトの別の投稿から見つけたこのMSDNリンクからこの小さな冒険を読んで始めました。

私たちが使用した現在の方法...一日の初めに...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を使用することは、これを1日中行うのに最も遅い方法でした。)

    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ではなく文字列をループしたりするなど、他のさまざまな方法を試しました。

ですから、すべての人への私の質問は、これをさらに速くすることはできますか?私は何が欠けていますか?

4

5 に答える 5

1

一部のルックアップを減らすことで、もう少し速度を上げることができる場合があります。これを例にとってみましょう:

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

メソッドは.ContainsO(n)です。最悪の場合、何も見つからずに文字列全体のすべての文字をトラバースするため、配列内の各文字に対して少なくとも1回トラバースする必要があるため、その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

これにより、charがp_Message最大2回(トラバースに1回、文字列コンストラクターがchar配列をコピーするときに1回)トラバースされ、この関数がO(n)になります。

于 2010-11-30T22:34:57.083 に答える
0

StringBuilderReplace.NETで最速の()関数を提供します。

于 2010-11-30T22:12:32.943 に答える
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

ベンチマークは、スローする文字列の種類に大きく依存することに注意してください。したがって、可能な限り最も代表的なサンプル(および適切なサイズのサンプルである必要があります)を使用していることを確認してください。

于 2010-11-30T22:21:28.727 に答える
0

このを見てください。2つの方法を比較するいくつかのベンチマーク統計があります。

于 2010-11-30T22:22:07.523 に答える
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
于 2010-11-30T22:39:26.423 に答える