Вопрос

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

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

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

Итак, мой вопрос ко всему: могу ли я сделать это еще быстрее? Что мне не хватает?

Это было полезно?

Решение

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

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

А .Contains Метод o (n). В худшем случае вы собираетесь пересечь все чары во всей струне, ничего не найдете, поэтому вы ожидаете пройти хотя бы один раз для каждого персонажа в вашем массиве, так что он (нм), где n - длина Ваша строка и m - это количество Chars, которые вы заменяете.

Вы можете получить немного лучшую производительность, выполняя следующее (мой 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() Функция в .net.

Пара общих заметок здесь:

  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

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

Посмотри на это пример. Анкет Он имеет некоторую эталонную статистику, сравнивая два метода.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top