Замена символов в строках в VB.NET
как быстро я могу заменить символы в строке?
Итак, фон по этому вопросу таков: у нас есть несколько приложений, которые взаимодействуют друг с другом и с приложениями клиентов через сокеты. Эти сообщения сокетов содержат непечатаемые символы(например, chr (0)), которые необходимо заменить предопределенной строкой (e.g " {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 и используя строку.replace дает более быстрые результаты. (На самом деле, использование StringBuilder было самый медленный способ делать это весь день.)
p_Message = p_Message.Replace(Chr(0), "{NUL}")
p_Message = p_Message.Replace(Chr(1), "{SOH}")
зная, что не каждое сообщение должно пройти через этот процесс, я подумал, что это сэкономит время, чтобы не обрабатывать те сообщения, которые могут быть опущены. Поэтому, используя регулярные выражения, я сначала искал строку, а затем определял, нужно ли ее обрабатывать или нет. Это было примерно то же самое, что использовать строку.замените, в основном мытье от экономии времени не обработки всех строк, но потери времени от проверка их всех регулярными выражениями.
затем было предложено попробовать использовать некоторые массивы, которые сопоставляли свои индексы со старыми и новыми, и использовать их для обработки сообщений. Значит, что-то вроде этого...
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 ответов
возможно, вы сможете выжать немного больше скорости, уменьшив некоторые запросы. Взять например это:
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).
Это должно быть быстрее:
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
пара общих замечаний здесь:
- вы можете улучшить функцию поиска, используя простой
.IndexOf()
или.Contains()
поиск, так как вы ищете только отдельные символы. - вы можете улучшить общую пропускную способность, вернув объект StringBuilder из вашей функции напрямую и предоставив перегрузки для других функций, которые принимают 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
обратите внимание, что ваши бенчмарки будут сильно зависеть от того, какие строки вы бросаете на него, поэтому убедитесь, что вы используете наиболее репрезентативный образец (и он должен быть хорошего размера).
посмотри пример. Он имеет некоторую базовую статистику, сравнивающую эти два метода.