Domanda

Quanto velocemente posso sostituire caratteri di una stringa?

Quindi, sullo sfondo a questa domanda è questa: Abbiamo un paio di applicazioni che comunicano tra loro e con le applicazioni dei clienti attraverso i socket. Questi messaggi di socket contengono caratteri non stampabili (ad esempio chr (0)), che hanno bisogno di ottenere sostituito con una stringa predeterminata (ad esempio, "{Nul}"}, in quanto i messaggi di socket sono conservati in un file di log. Su un lato nota no, ogni messaggio di log dovrà avere caratteri sostituiti.

Ora ho iniziato su questa lettura piccola avventura da questo link MSDN che ho trovato da un posto diverso da questo sito.

L'attuale metodo che abbiamo usato ... all'inizio della giornata ... stava usando StringBuilder per verificare la presenza di tutti i possibili sostituti, come ...

    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

Ora, come i punti di post del blog fuori lasciando StringBuilder fuori e utilizzando String.Replace fa resa più veloce risultati. (In realtà, utilizzando StringBuilder è stato il metodo più lento di fare questo per tutto il giorno.)

    p_Message = p_Message.Replace(Chr(0), "{NUL}")
    p_Message = p_Message.Replace(Chr(1), "{SOH}")

Sapendo che non ogni messaggio avrebbe bisogno di passare attraverso questo processo ho pensato che sarebbe risparmiare tempo per non dover elaborare quei messaggi che potrebbero essere lasciati fuori. Quindi, utilizzando le espressioni regolari in primo luogo ho cercato la corda e poi determinato se aveva bisogno di essere trasformati o no. Questo è stato più o meno come utilizzando lo String.Replace, in pratica un lavaggio di salvare il tempo di elaborazione, non tutte le corde, ma perdere tempo da tutti loro controllo con le espressioni regolari.

Poi è stato suggerito di provare a utilizzare alcuni array che ha abbinato i loro indici con il vecchio e il nuovo e l'uso che per elaborare i messaggi. Quindi sarebbe qualcosa di simile ...

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

Questo finora è stato il modo più veloce che ho trovato per elaborare questi messaggi. Ho provato vari altri modi di andare su questo così come la conversione della stringa in ingresso in un array di caratteri e confrontando insieme anche cercando di scorrere la stringa, anziché alla chrArray.

Quindi la mia domanda a tutti è: Posso fare questo più veloce ancora? Che cosa mi manca?

È stato utile?

Soluzione

Si potrebbe essere in grado di spremere un po 'più di velocità, riducendo alcune ricerche. Prendiamo ad esempio questo:

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

Il metodo .Contains è O (n). Nel peggiore dei casi, si sta andando ad attraversare tutti i caratteri della stringa completa senza trovare nulla, quindi ci si aspetta di attraversare almeno una volta per ogni carattere nella propria matrice, quindi la sua O (nm), dove n è la lunghezza del la stringa e m è il numero di caratteri che si sta sostituendo.

Si potrebbe ottenere un po 'migliore performance facendo la seguente (il mio VB-fu è arrugginito, non è stato testato;)):

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

Questo attraversare caratteri in p_Message al massimo due volte (una volta per traslazione, una volta quando le copie costruttore stringa char), rendendo questa funzione O (n).

Altri suggerimenti

Questo dovrebbe anche essere più veloce:

    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

offerte StringBuilder il Replace più veloce () in .NET.

Un paio di note generali qui:

  1. Si potrebbe essere in grado di migliorare la funzione di ricerca utilizzando un .IndexOf() normale o di ricerca .Contains(), visto che tu sei solo alla ricerca di singoli caratteri.
  2. Si potrebbe essere in grado di migliorare la vostra produttività totale restituendo l'oggetto StringBuilder dalla vostra funzione direttamente e fornendo sovraccarichi per le altre funzioni che accettano stringbuilders come input o chiamando .ToString () da qualche parte più avanti nel processo (NOTA: È possibile anche chiamare .ToString () su oggetti che sono già stringhe)
  3. Si dovrebbe essere in grado di migliorare ulteriormente le prestazioni / rendimento utilizzando inoltre uno StringReader / TextReader la catena e continuare a trattare tutto come torrenti che mantenere sempre superato la catena.

A meno è possibile modificare il metodo di finale in questo modo:

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

Si noti che i tuoi punti di riferimento dipenderà in gran parte dal tipo di stringhe che stai buttando a esso, in modo da assicurarsi che si sta utilizzando il campione più rappresentativo (e dovrebbe essere un buon campione di dimensioni) possibile.

Date un'occhiata a questo esempio . Ha alcune statistiche benchmark a confronto i due metodi.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top