C#

C# Replace

.NET Array Collections File String Async Cast DataTable DateTime Dictionary Enum Exception For Foreach IEnumerable If IndexOf Lambda LINQ List Parse Path Process Property Regex Replace Sort Split StringBuilder Substring Switch Tuple

Replace

Replace. A string contains incorrect chars. It has XYZ but we want ABC. Replace helps with this puzzle. It swaps those substrings.


Go copyright

In programs, every replacement made results in a new string. Unneeded Replace calls should be removed. Replace changes all occurrences. It handles char replacements.


String

A simple example. To begin, we invoke the Replace method. Please note that we must assign Replace's result to a variable. It does not modify the string in-place.

Here:We introduce a const string literal. We call Replace() on this character data, and it returns a new string object.

WriteLine:We pass the "output" string to Console.WriteLine to print it to the console window.

Based on:

.NET 4.5

C# program that uses Replace

using System;

class Program
{
    static void Main()
    {
	const string input = "_::_pagitica";
	Console.WriteLine(input);

	// Call Replace on the string.
	// ... We must assign the result of the Replace call.
	string output = input.Replace("_::_", "Areo");
	Console.WriteLine(output);
    }
}

Output

_::_pagitica
Areopagitica
All extension method

Every instance. This is important. The Replace method changes every instance of the specified substring. This can sometimes result in unexpected behavior. The first match is not targeted.

Here:To demonstrate, the console program replaces the word "Net" with the word "Basket." There is no need to call Replace two times.

Note:A second Replace() would not do anything. It would just result in CPU cycles being wasted.

C# program that causes multiple replacements

using System;

class Program
{
    static void Main()
    {
	const string s = "Dot Net Perls is about Dot Net.";
	Console.WriteLine(s);

	// We must assign the result to a variable.
	// ... Every instance is replaced.
	string v = s.Replace("Net", "Basket");
	Console.WriteLine(v);
    }
}

Output

Dot Net Perls is about Dot Net.
Dot Basket Perls is about Dot Basket.
Letters of the alphabet: ABC

StringBuilder. This is an important type. With StringBuilder, Replace works the same way as with strings, but we don't need to assign the result to anything.

Here:In this example, we create a StringBuilder. We use the constructor to initialize the StringBuilder with a short sentence.

Replace:We replace the word "This" with the word "Here." The result has the new word in place of the old word.

C# program that uses StringBuilder

using System;
using System.Text;

class Program
{
    static void Main()
    {
	const string s = "This is an example.";

	// Create new StringBuilder from string.
	StringBuilder b = new StringBuilder(s);
	Console.WriteLine(b);

	// Replace the first word.
	// ... The result doesn't need assignment.
	b.Replace("This", "Here");
	Console.WriteLine(b);

	// Insert the string at the beginning.
	b.Insert(0, "Sentence: ");
	Console.WriteLine(b);
    }
}

Output

This is an example.
Here is an example.
Sentence: Here is an example.
Exclamation mark

Problem. Replace() creates a string copy each time it is called. This can lead to measurable performance problems. MSDN notes that Replace returns a new string.

This method does not modify the value of the current instance. Instead, it returns a new string in which all occurrences of oldValue are replaced by newValue.

String.Replace Method: MSDN
StringBuilder

Rewrite. It is usually easy to rewrite wasteful string Replace code with StringBuilder. Here I show the original code that uses string and then the new StringBuilder code.

Version A:This version ends up creating many string copies. It replaces whitespace around punctuation.

NewLineEmpty

Version B:MinifyB is similar but uses StringBuilder. It does the same replacements as version A.

String Replace example: C#

/// <summary>
/// A - Eliminates extra whitespace.
/// </summary>
static string MinifyA(string p)
{
    p = p.Replace("  ", string.Empty);
    p = p.Replace(Environment.NewLine, string.Empty);
    p = p.Replace("\\t", string.Empty);
    p = p.Replace(" {", "{");
    p = p.Replace(" :", ":");
    p = p.Replace(": ", ":");
    p = p.Replace(", ", ",");
    p = p.Replace("; ", ";");
    p = p.Replace(";}", "}");
    return p;
}

StringBuilder Replace example: C#

/// <summary>
/// B - Eliminates extra whitespace.
/// </summary>
static string MinifyB(string p)
{
    StringBuilder b = new StringBuilder(p);
    b.Replace("  ", string.Empty);
    b.Replace(Environment.NewLine, string.Empty);
    b.Replace("\\t", string.Empty);
    b.Replace(" {", "{");
    b.Replace(" :", ":");
    b.Replace(": ", ":");
    b.Replace(", ", ",");
    b.Replace("; ", ";");
    b.Replace(";}", "}");
    return b.ToString();
}
Performance

Benchmark. We next see if there is a difference between version A and B above. The version that avoids copies, with StringBuilder, is many times faster.

Tip:Neither method is close to optimal, as internally each call to Replace must search the string.

Tip 2:This benchmark does demonstrate a clear advantage of StringBuilder. It does not show how to write a good CSS minify method.

Replace methods benchmark, 20 chars

Method A - String Replace:         5.60 seconds
Method B - StringBuilder Replace:  0.62 seconds [faster]

Replace methods benchmark, 1000 chars

Method A - String Replace:        21.80 seconds
Method B - StringBuilder Replace   4.89 seconds [faster]
Method

Argument performance. Here we test a program that calls Replace in four ways. The first two calls use char arguments. The second two calls use string arguments.

Note:Only the second and the fourth calls require that the string be changed in memory.

Char

Tip:Avoiding an object allocation has a performance benefit. And often this outweighs any extra CPU usage.

Result:Replace calls that use chars are faster. And if no change occurs, Replace will return faster.

C# program that benchmarks Replace

using System;
using System.Diagnostics;

class Program
{
    const int _max = 1000000;
    static void Main()
    {
	string test = "dotnetperls";
	var s1 = Stopwatch.StartNew();
	for (int i = 0; i < _max; i++)
	{
	    string t = test.Replace('x', 'y');
	}
	s1.Stop();
	var s2 = Stopwatch.StartNew();
	for (int i = 0; i < _max; i++)
	{
	    string t = test.Replace('d', 'y');
	}
	s2.Stop();
	var s3 = Stopwatch.StartNew();
	for (int i = 0; i < _max; i++)
	{
	    string t = test.Replace("x", "y");
	}
	s3.Stop();
	var s4 = Stopwatch.StartNew();
	for (int i = 0; i < _max; i++)
	{
	    string t = test.Replace("d", "y");
	}
	s4.Stop();

	Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000 * 1000) /
	    _max).ToString("0.00 ns"));
	Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000 * 1000) /
	    _max).ToString("0.00 ns"));
	Console.WriteLine(((double)(s3.Elapsed.TotalMilliseconds * 1000 * 1000) /
	    _max).ToString("0.00 ns"));
	Console.WriteLine(((double)(s4.Elapsed.TotalMilliseconds * 1000 * 1000) /
	    _max).ToString("0.00 ns"));
	Console.Read();
    }
}

Output

 13.00 ns    Char Replace, no change
 47.75 ns    Char Replace, change
 73.26 ns    String Replace, no change
117.07 ns    String Replace, change
Logic

Logic optimization. Replace can be optimized. Suppose in our program many string replacements must be done. But often nothing is changed in actual strings.

Version A:Let's look at the initial version of the method. It runs four Replace calls on the formal parameter to the method.

Version B:The second version uses the Contains method around all the Replace calls with the specified common string literal.

Contains

Tip:In version B, the first two Replace calls are only run when the common pattern is found. Often the string is searched less.

First version of method: C#

static string A(string text)
{
    text = text.Replace("<span>Cat ", "<span>Cats ");
    text = text.Replace("<span>Clear ", "<span>Clears ");
    text = text.Replace("<span>Dog ", "<span>Dogs ");
    text = text.Replace("<span>Draw ", "<span>Draws ");
    return text;
}

Second version of method: C#

static string B(string text)
{
    if (text.Contains("<span>C"))
    {
	text = text.Replace("<span>Cat ", "<span>Cats ");
	text = text.Replace("<span>Clear ", "<span>Clears ");
    }
    if (text.Contains("<span>D"))
    {
	text = text.Replace("<span>Dog ", "<span>Dogs ");
	text = text.Replace("<span>Draw ", "<span>Draws ");
    }
    return text;
}
Split

Split. Often strings contains invalid syntax. We can use Replace to fix incorrect parts of a string before using Split to separate it.

Split
Newline

Whitespace. We often need to remove or change whitespace in strings, particularly those read in from files.
We can handle tabs,
spaces
and line breaks.

Whitespace

A summary. As strings are immutable, Replace does not modify them. It instead creates a new copy with the replacements applied. It replaces all instances of a match.


Summary: 300, 200 and 100

For frequent replacement, StringBuilder is much faster. It avoids copies. Other than implementation, the methods are used in a similar way, with the same arguments.