String.Replace () vs. StringBuilder.Replace ()

I have a line in which I need to replace markers with values ​​from a dictionary. It should be as effective as possible. Running a loop with string.replace will just consume memory (strings are immutable, remember). Would StringBuilder.Replace () be better since it was designed to work with string manipulations?

I was hoping to avoid RegEx costs, but if it is more efficient, so be it.

Note. I'm not interested in the complexity of the code, just how fast it works and the memory it consumes.

Average statistics: 255-1024 characters in length, 15-30 keys in the dictionary.

+63
c # replace
Jun 29 '11 at 17:04
source share
9 answers

Using RedGate Profiler Using the Following Code

class Program { static string data = ""; static Dictionary<string, string> values; static void Main(string[] args) { Console.WriteLine("Data length: " + data.Length); values = new Dictionary<string, string>() { { "ab", "aa" }, { "jk", "jj" }, { "lm", "ll" }, { "yz", "zz" }, { "ef", "ff" }, { "st", "uu" }, { "op", "pp" }, { "x", "y" } }; StringReplace(data); StringBuilderReplace1(data); StringBuilderReplace2(new StringBuilder(data, data.Length * 2)); Console.ReadKey(); } private static void StringReplace(string data) { foreach(string k in values.Keys) { data = data.Replace(k, values[k]); } } private static void StringBuilderReplace1(string data) { StringBuilder sb = new StringBuilder(data, data.Length * 2); foreach (string k in values.Keys) { sb.Replace(k, values[k]); } } private static void StringBuilderReplace2(StringBuilder data) { foreach (string k in values.Keys) { data.Replace(k, values[k]); } } } 
  • String.Replace = 5.843ms
  • StringBuilder.Replace # 1 = 4.059ms
  • Stringbuilder.Replace # 2 = 0.461ms

String Length = 1456

stringbuilder # 1 creates a string constructor in a method, and # 2 doesn’t make the difference in performance the same, most likely, since you are simply moving this work out of the method. If you start with stringbuilder instead of a string, then instead of # 2 it may be instead.

As for the memory using the RedGateMemory profiler, you have nothing to worry about until you go into MANY replacement operations in which the builder will build as a whole.

+60
Jun 29 '11 at 17:40
source share

This may be useful:

http://blogs.msdn.com/b/debuggingtoolbox/archive/2008/04/02/comparing-regex-replace-string-replace-and-stringbuilder-replace-which-has-better-performance.aspx

The short answer seems to be that String.Replace is faster, although this may have a greater effect on your overhead in terms of memory / garbage.

+9
Jun 29 '11 at 17:11
source share

Yes, StringBuilder will give you both a speed boost and memory (mainly because it will not instantiate a string every time you manipulate it - StringBuilder always works with the same object), here is the link

+6
Jun 29 '11 at 17:14
source share

Would stringbuilder.replace be better [than String.Replace]

Yes, much better. And if you can evaluate the upper bound for a new line (it looks the way you can), then it will probably be fast enough.

When you create it like:

  var sb = new StringBuilder(inputString, pessimisticEstimate); 

then StringBuilder does not have to redistribute its buffer.

+4
Jun 29 '11 at 17:12
source share

Converting data from String to StringBuilder and vice versa will take some time. If you perform only one replacement operation, this time cannot be offset by the performance improvement inherent in StringBuilder. On the other hand, if one converts a string to a StringBuilder, it performs many Replace operations on it and converts it back to the end, the StringBuilder approach can be faster.

+1
Jun 29 '11 at 17:17
source share

Instead of performing 15-30 replace operations on the entire line, it would be more efficient to use something like a trie structure to store the dictionary. You can then scroll through the input line once to complete the entire search / replace.

+1
Jun 29 '11 at 17:32
source share

This will depend on how many markers are present in a given line on average.

Key search performance is likely to be the same between StringBuilder and String, but StringBuilder will win if you have to replace many tokens on the same line.

If you expect only one or two markers per line on average, and your vocabulary is small, I'll just go to String.Replace.

If there are many tokens, you can define your own syntax for identifying tokens — for example, enclosing a matching exit rule for a literal bracket in curly braces. Then you can implement a parsing algorithm that repeats through line characters once, recognizing and replacing each marker found. Or use a regex.

+1
Jun 29 '11 at 18:56
source share

My two cents here, I wrote a couple of lines of code to check how each method works, and, as expected, the result is “dependent”.

For longer strings, Regex seems to work better; for shorter strings, String.Replace does. I see that using StringBuilder.Replace not very useful, and if it is mistakenly used, it can be lethal in the GC perspective (I tried to split one instance of StringBuilder ).

Check out the StringReplaceTests GitHub repo .

+1
Dec 02 '15 at 22:51
source share

The problem with @DustinDavis answer is that it recursively works on a single line. If you do not plan to do back-and-forth manipulations, you really should have separate objects for each manipulation case in this type of test.

I decided to create my own test because I found some conflicting answers all over the Internet, and I wanted to be absolutely sure. The program I'm working on processes a lot of texts (files with tens of thousands of lines in some cases).

So here is a quick method that you can copy and paste and see for yourself, which is faster. You may need to create your own text file for testing, but you can easily copy and paste text from anywhere and make a sufficiently large file for you:

 using System; using System.Diagnostics; using System.IO; using System.Text; using System.Windows; void StringReplace_vs_StringBuilderReplace( string file, string word1, string word2 ) { using( FileStream fileStream = new FileStream( file, FileMode.Open, FileAccess.Read ) ) using( StreamReader streamReader = new StreamReader( fileStream, Encoding.UTF8 ) ) { string text = streamReader.ReadToEnd(), @string = text; StringBuilder @StringBuilder = new StringBuilder( text ); int iterations = 10000; Stopwatch watch1 = new Stopwatch.StartNew(); for( int i = 0; i < iterations; i++ ) if( i % 2 == 0 ) @string = @string.Replace( word1, word2 ); else @string = @string.Replace( word2, word1 ); watch1.Stop(); double stringMilliseconds = watch1.ElapsedMilliseconds; Stopwatch watch2 = new Stopwatch.StartNew(); for( int i = 0; i < iterations; i++ ) if( i % 2 == 0 ) @StringBuilder = @StringBuilder .Replace( word1, word2 ); else @StringBuilder = @StringBuilder .Replace( word2, word1 ); watch2.Stop(); double StringBuilderMilliseconds = watch1.ElapsedMilliseconds; MessageBox.Show( string.Format( "string.Replace: {0}\nStringBuilder.Replace: {1}", stringMilliseconds, StringBuilderMilliseconds ) ); } } 

I got this line. Replace () 20% faster each time, replacing 8-10 letter words. Try it yourself if you want your own empirical data.

+1
May 12 '16 at 18:07
source share



All Articles