Замена символов в строках в VB.NET - PullRequest
6 голосов
/ 01 декабря 2010

Как быстро я могу заменить символы в строке?

Итак, история вопроса такова: у нас есть пара приложений, которые взаимодействуют друг с другом и с клиентскими приложениями через сокеты. Эти сообщения сокетов содержат непечатаемые символы (например, 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 было самым медленным способом делать это весь день.)

    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 ]

1 голос
/ 01 декабря 2010

Вы можете выжать немного больше скорости, уменьшив некоторые поиски.Для примера возьмем:

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

Метод .Contains - O (n).В худшем случае вы будете проходить все символы во всей строке, не находя ничего, поэтому вы ожидаете пройти хотя бы один раз для каждого символа в вашем массиве, поэтому его O (нм), где 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 не более двух раз (один раз для обхода, один раз, когда строковый конструктор копирует массив символов), делая эту функцию O (n).

0 голосов
/ 01 декабря 2010

Это также должно быть быстрее:

    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
0 голосов
/ 01 декабря 2010

Несколько общих замечаний здесь:

  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

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

0 голосов
/ 01 декабря 2010

Посмотрите на этот пример .В нем есть сравнительная статистика, сравнивающая два метода.

0 голосов
/ 01 декабря 2010

StringBuilder предлагает самую быструю функцию Replace () в .NET.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...