Optimize string replacements with StringBuilder and observe patterns of best usage and related benchmarks. You want to see a real-world example of using StringBuilder.Replace() in ASP.NET, and how it can greatly improve runtime performance. Improve your string handling and also your general knowledge of StringBuilder.
Here we will look at some basics of StringBuilder and its Replace and Insert methods, before we get to the interesting real-world benchmarks and some notes about best practices. The following code (pretty self-explanatory) shows the basics of Replace and Insert and how they might be used.
using System; using System.Collections.Generic; using System.Linq; using System.Text; // Important to include this. using System.Diagnostics; // For Debug write. /// <summary> /// Example class for StringBuilder. /// </summary> static class BuilderReplace { /// <summary> /// Runs example code. /// </summary> public static void ReplaceExamples() { string value = "This is an example."; StringBuilder builder = new StringBuilder(value); // Pass string to constructor. Debug.WriteLine(builder); // "This is an example." // Replace first word with "Here". builder.Replace("This", "Here"); Debug.WriteLine(builder); // "Here is an example." builder.Insert(0, "Sentence: "); Debug.WriteLine(builder); // "Sentence: Here is an example." } }
Strings cannot actually be changed--only new ones can be created. Therefore, Replace will repeatedly create new strings. StringBuilder, however, can be changed internally and no new copies will be created on Replace or Insert.
Quite easily, if your code currently uses string Replace. Let's look at some real-world code, first with the StringBuilder version, and then with the old string Replace version. The benchmarks follow (the StringBuilder is 4-6 times faster).
/// <summary>
/// Eliminates extra whitespace from style sheets. Uses StringBuilder and is fast.
/// </summary>
public static string Minify(string body)
{
StringBuilder builder = new StringBuilder(body);
builder = builder.Replace(" ", string.Empty);
builder = builder.Replace(Environment.NewLine, string.Empty);
builder = builder.Replace("\\t", string.Empty);
builder = builder.Replace(" {", "{");
builder = builder.Replace(" :", ":");
builder = builder.Replace(": ", ":");
builder = builder.Replace(", ", ",");
builder = builder.Replace("; ", ";");
builder = builder.Replace(";}", "}");
return builder.ToString();
}
Slow version follows. As promised, here is the slower version. Note that this code is very good overall, and credit for it goes to Zack Owens at weblogs.asp.net (there's other neat stuff there).
/// <summary>
/// This is the string Replace version, which is slower.
/// </summary>
public static string Minify(string body)
{
body = body.Replace(" ", string.Empty);
body = body.Replace(Environment.NewLine, string.Empty);
// (Read more about Environment.NewLine.)
body = body.Replace("\\t", string.Empty);
body = body.Replace(" {", "{");
body = body.Replace(" :", ":");
body = body.Replace(": ", ":");
body = body.Replace(", ", ",");
body = body.Replace("; ", ";");
body = body.Replace(";}", "}");
return body;
}
As Zack says in his post, this code may run repeatedly on the ASP.NET server. Therefore it seems that making it more efficient is worthwhile, if doing so is easy. The first graph below shows the time required for a small string, and the second a large string.
10,000 iterations tested. The tests were run with 10,000 iterations each. Probably each replace resulted in some change being made to the string. The methods returned the same values.
Rewrite your string Replace routines to use StringBuilder replace. (Similarly, use Insert where appropriate.) As I note in my StringBuilder secrets page, however, use your best judgment. Reading about others' work may help make your own better. StringBuilder has some overhead, but its advantages here justified that.