Замена символов в строках в 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

StringBuilder предлагает самый быстрый Replace () функция in .Сеть.


пара общих замечаний здесь:

  1. вы можете улучшить функцию поиска, используя простой .IndexOf() или .Contains() поиск, так как вы ищете только отдельные символы.
  2. вы можете улучшить общую пропускную способность, вернув объект StringBuilder из вашей функции напрямую и предоставив перегрузки для других функций, которые принимают stringbuilders в качестве входных данных или вызова .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

обратите внимание, что ваши бенчмарки будут сильно зависеть от того, какие строки вы бросаете на него, поэтому убедитесь, что вы используете наиболее репрезентативный образец (и он должен быть хорошего размера).


посмотри пример. Он имеет некоторую базовую статистику, сравнивающую эти два метода.