vb.netの文字列の文字置換
-
29-09-2019 - |
質問
文字列内の文字をどのくらい速く交換できますか?
したがって、この質問の背景は次のとおりです。互いに、そしてソケットを介したクライアントのアプリケーションと通信するアプリケーションがいくつかあります。これらのソケットメッセージには、ソケットメッセージがログファイルに保持されているため、所定の文字列( "{nul}"})に置き換える必要がある印刷不可能な文字(chr(0)など)が含まれています。すべてのログメッセージは、文字を交換する必要があります。
今、私はこの小さな冒険を始めました この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を使用することは、これを一日中これを行う最も遅い方法でした。)
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
これはこれまでのところ、私がこれらのメッセージを処理するために私が見つけた最速の方法でした。私はこれを他のさまざまな方法で試しました。着信文字列を文字アレイに変換し、クロレイではなく文字列をループしようとすることと同様に比較しました。
それで、私のすべての質問は、これをさらに速くすることはできますか?何が足りないの?
解決
ルックアップを減らすことで、もう少し速度を絞ることができるかもしれません。たとえば、これを考えてみましょう:
If p_Message.Contains(chrArray(i).ToString) Then
.Contains
メソッドはO(n)です。最悪の場合、あなたは何も見つからずに文字列全体のすべてのcharを横断するので、あなたはあなたの配列内の各文字について少なくとも1回はトラバースすることを期待するので、そのo(nm)はnがの長さですあなたの文字列とmは、あなたが置き換えているcharの数です。
次のことをすると、パフォーマンスが少し良くなるかもしれません(私の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回(ストリングコンストラクターがcharアレイをコピーするときに1回、1回)、この関数o(n)を作成します。
他のヒント
これもより速くなるはずです:
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
StringBuilder
最速を提供します Replace
().NETの関数。
ここにいくつかの一般的なメモ:
- 平野を使用して検索機能を改善できる場合があります
.IndexOf()
また.Contains()
あなたは単一のキャラクターだけを探しているので、検索してください。 - 関数からStringBuilderオブジェクトを直接返すことにより、StringBuildersを入力としてStringBuildersを受け入れる他の機能のオーバーロードを提供するか、プロセスの後半で.toString()を呼び出すことにより、トータルスループットを改善できる場合があります(注:.ToStringを呼び出すこともできます。 ()すでに文字列であるオブジェクトについて)
- 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
ベンチマークは、投げている文字列の種類に大きく依存することに注意してください。そのため、最も代表的なサンプルを使用していることを確認してください(適切なサイズのサンプルである必要があります)。
これを見てください 例. 。 2つの方法を比較するいくつかのベンチマーク統計があります。