Contents
Introduction
It’s common to have data in one format, but want to change it to another. At a low level, this can often come down to doing string replacements – whether it’s tabs to commas for delimited files, more complicated munges, it’s a useful trick to have up your sleeve.
Simplest Replace
It doesn’t get much simpler than using the String.Replace() method:
var text = "Hello World"; var text2 = text.Replace("World", "Everyone"); Console.WriteLine($"{text} -> {text2}"); \\ This code outputs: \\ Hello World -> Hello Everyone
Case Insensitive Search and Replace
By default, String.Replace is case sensitive, it cares about capitalization:
var text = "Hello World"; var text2 = text.Replace("hello", "Hi"); Console.WriteLine($"{text} -> {text2}"); // This code outputs: // Hello World -> Hello World
The replace attempt fails because “Hello” does not match “hello” (it’s case sensitive). If you’re after a case insensitive replace, try this:
var text = "Hello World"; var s = StringComparison.CurrentCultureIgnoreCase; var text2 = text.Replace("hello", "Yo", s); Console.WriteLine($"{text} -> {text2}"); // This code outputs: // Hello World -> Yo World
Replacing a Single Character in a String
String.Replace also has another overload, allowing the replacement of a single character.
var text = "Hello World"; var text2 = text.Replace('e', 'a'); Console.WriteLine($"{text} -> {text2}"); // This code outputs: // Hello World -> Hallo World
There’s a gotcha though, you can’t replace a char with a string or a string with a char, the types of the oldValue and new value have to match. If you try and mix the types you’ll end up with an error:
var text = "Hello World"; var text2 = text.Replace('e', "abc"); Console.WriteLine($"{text} -> {text2}"); // This code throws a compile time error: // Compilation error (line 3, col 31): Argument 2: cannot convert from 'string' to 'char'
Replace the First Instance of a String
By default, String.Replace does a global replace; it will replace all instances of the old value with the new value:
var text = "The ants go marching two by two..."; var text2 = text.Replace("two", "three"); Console.WriteLine(text); Console.WriteLine(text2); \\ This code outputs: \\ The ants go marching two by two... \\ The ants go marching three by three...
What if we don’t want all instances replaced? we just want to replace the first instance then stop?
If you only want to replace the first instance of a string, then I’m afraid you need to step out of the comfort zone of String.Replace. You can either roll your own method, or you can use regex.replace:
Replace First Instance – Roll Your Own
The following code snippet has been influenced heavily by this Stack Overflow answer:
static string ReplaceFirst(string text, string oldValue, string newValue) { int pos = text.IndexOf(oldValue); return pos < 0 ? text // a negative value indicates oldValue was not found : text.Substring(0, pos) // Everything up to the oldValue + newValue + text.Substring(pos + oldValue.Length); // Everything after the oldValue }
It can then be used as follows:
var text = "The ants go marching two by two..."; var text2 = Program.ReplaceFirst(text, "two", "three"); Console.WriteLine(text); Console.WriteLine(text2); // This code outputs: // The ants go marching two by two... // The ants go marching three by two...
Replace First Instance – Using Regex Replace
By using the Regex class, we can achieve a one time replacement without writing our own code:
using System.Text.RegularExpressions; var text = "Hello Hello Hello"; var regex = new Regex("Hello"); var text2 = regex.Replace(text, "Hi", 1); Console.WriteLine($"{text} -> {text2}"); // This code outputs // Hello Hello Hello -> Hi Hello Hello
In the above example we passed a 1 as the last argument to regex.Replace, this argument is actually a count and we can use it to specify how many times to run the replacement:
var text = "Hello Hello Hello"; var regex = new Regex("Hello"); var text2 = regex.Replace(text, "Yo", 2); Console.WriteLine($"{text} -> {text2}"); // This code outputs // Hello Hello Hello -> Yo Yo Hello
Regular Expression Replace
We’ve seen above how the Regex.Replace class class can be used to replace a single, or a specified number of occurrences of a pattern, but that’s just the tip of the iceberg when it comes to the power of regular expressions. They really deserve their own post, but for now I’ll give you a few examples to whet your appetite:
Case Insensitive Replace using Regex.Replace
var text = "Hello world"; var text2 = Regex.Replace(text, "WORLD", "Everyone", RegexOptions.IgnoreCase); Console.WriteLine($"{text} -> {text2}"); // This code outputs // Hello world -> Hello Everyone
Wildcard Replace Using Regex.Replace
var text = "Hello Hallo Hullo"; var text2 = Regex.Replace(text, "H.llo", "Yo"); Console.WriteLine($"{text} -> {text2}"); // This code outputs // Hello Hallo Hullo -> Yo Yo Yo
String Replace in Place
Note that in C# string are immutable. This means that any search and replace (whether using built in methods, regex methods, or rolling your own code) are going to return a new string with the requested substitutions. Now imagine your input string takes up 100MB of memory, and you’re running 10 or 20 replacements on it. Each time you do a replace you’re allocating memory for the new copy of the string. It’s easy to see how you could quickly use up significant memory resources, so be careful when you’re dealing with large strings!
Thankfully, the StringBuilder class was designed with this situation in mind. It behaves a lot like a string, but it’s actually a mutable sequence of characters. That means we can modify it in place without allocating new memory for a copy of the original string:
In Place Replace using StringBuilder.Replace
var text = new StringBuilder("Hello Hello Hello"); Console.WriteLine($"Before: {text}"); text.Replace("Hello", "Ho"); Console.WriteLine($"After: {text}"); // This code outputs // Before: Hello Hello Hello // After: Ho Ho Ho
It’s worth looking at the docs to see what can be done with StringBuilder.Replace, it’s not as fully featured as String.Replace or Regex.Replace, but if you’re dealing with large strings and memory is an issue, then it’s a great tool to be aware of.
Conclusion
We’ve seen how to do simple replacements with String.Replace, how to replace the first (or first few!) instances of a pattern in a couple of ways, we’ve looked at case insensitive searches, touched on regular expressions and even considered ways to limit memory usage when running a search and replace on very large strings.
I really hope you’ve learned something from this deep dive into string replacing in C#. As always, if you feel I’ve missed anything, or just want to say hi, let me know in the comments!