Le remplacement des caractères dans les chaînes en VB.NET
-
29-09-2019 - |
Question
Combien de temps puis-je remplacer les caractères dans une chaîne?
Ainsi, le fond sur cette question est la suivante: Nous avons deux ou trois applications qui communiquent entre eux et avec les applications de ses clients par le biais de prises. Ces messages de socket contiennent des caractères non-imprimables (par exemple chr (0)) qui ont besoin de se remplacer par une chaîne prédéterminée (par exemple « {Nul} »}, parce que les messages de socket sont conservés dans un fichier journal. Sur une note latérale, non chaque message de journal devra avoir remplacé les caractères.
Maintenant, je commencé sur cette petite lecture d'aventure ce lien MSDN que j'ai trouvé à partir d'un autre poste de ce site.
La méthode actuelle, nous avons utilisé ... au début de la journée ... utilisait StringBuilder pour vérifier tous les remplacements possibles tels que ...
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
Maintenant, comme les points de billet de blog en laissant StringBuilder à l'aide et String.replace ne donne des résultats plus rapides. (En fait, en utilisant StringBuilder est la méthode la plus lente de le faire toute la journée.)
p_Message = p_Message.Replace(Chr(0), "{NUL}")
p_Message = p_Message.Replace(Chr(1), "{SOH}")
Sachant que pas chaque message aurait besoin de passer par ce processus, je pensais que ce serait de gagner du temps de ne pas avoir à traiter ces messages qui pourraient être laissés de côté. Donc, en utilisant des expressions régulières j'ai cherché la chaîne, puis déterminé si elle devait être traitée ou non. Il était environ le même que l'utilisation du String.replace, essentiellement un lavage de sauver le temps de ne pas traiter toutes les chaînes, mais de perdre du temps de les vérifier toutes les expressions régulières.
Ensuite, il a été suggéré d'essayer d'utiliser des tableaux qui correspondent à leurs index avec l'ancien et le nouveau et l'utiliser pour traiter les messages. Donc, ce serait quelque chose comme ça ...
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
a été jusqu'ici le plus rapide que j'ai trouvé pour traiter ces messages. J'ai essayé d'autres façons d'aller à ce sujet ainsi que la conversion de la chaîne entrant dans un tableau de caractères et de comparer avec en essayant de boucle à travers la chaîne plutôt que le chrArray.
Alors ma question à tous est: Puis-je faire cela plus rapidement encore? Qu'est-ce que je manque?
La solution
Vous pourriez être en mesure de faire sortir un peu plus de vitesse en réduisant certaines recherches. Prenons par exemple ceci:
If p_Message.Contains(chrArray(i).ToString) Then
La méthode de .Contains
est O (n). Dans le pire des cas, vous allez parcourir tous les caractères de la chaîne entière sans trouver quoi que ce soit, si vous vous attendez à traverser au moins une fois pour chaque caractère dans votre tableau, de sorte que son O (nm) où n est la longueur votre chaîne et m est le nombre de caractères que vous remplacez.
Vous pouvez obtenir un peu de meilleures performances à faire ce qui suit (ma VB-fu est rouillé, n'a pas été testé;)):
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
Ceci va traverser caractère en p_Message
au plus deux fois (une fois pour le déplacement, une fois lorsque les copies du constructeur de la chaîne de tableau de caractères), ce qui rend cette fonction O (n).
Autres conseils
Cela devrait également être plus rapide:
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
offre la plus rapide fonction Replace
() dans .NET.
Quelques notes générales ici:
- Vous pourriez être en mesure d'améliorer la fonction de recherche en utilisant un ou
.IndexOf()
recherche.Contains()
plaine, puisque vous êtes à la recherche que pour un seul caractère. - Vous pourriez être en mesure d'améliorer votre débit total en retournant l'objet StringBuilder de votre fonction directement et en fournissant des surcharges pour d'autres fonctions qui acceptent stringbuilders en entrée ou en appelant .toString () quelque part plus tard dans le processus (note: Vous pouvez également appel .ToString () sur les objets qui sont déjà des chaînes)
- Vous devez certainement être en mesure d'améliorer les performances / débit plus loin en utilisant un StringReader / TextReader plus haut dans la chaîne et continuer à tout traiter comme cours d'eau qui continue à recevoir laissé passer la chaîne.
À tout le moins, vous pouvez modifier votre méthode finale de cette façon:
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
Notez que vos points de repère dépendra en grande partie du type de chaînes que vous jetez à elle, alors assurez-vous que vous utilisez le plus échantillon représentatif (et il devrait être un bon échantillon de taille) possible.
Jetez un oeil à cette exemple . Il a des statistiques de référence comparant les deux méthodes.