A C# string is immutable, which means its contents never change after you create it. Every method that appears to modify a string actually returns a new string with the changes, leaving the original intact. The examples in this article store each result in a new variable so you can see both the source and the modified value.
Choose the technique that matches your scenario: replace known text, trim whitespace, remove a span of characters, replace text that matches a pattern, or edit individual characters.
Replace known text
The System.String.Replace method substitutes every occurrence of one string with another and returns the result as a new string:
sample · csharpdocs/csharp/fundamentals/strings/common-tasks/snippets/modify/Program.csReplace
using System.Text.RegularExpressions;
namespace ModifyStrings;
public static class Program
{
public static void Main()
{
ReplaceText();
Console.WriteLine();
ReplaceCharacters();
Console.WriteLine();
TrimWhitespace();
Console.WriteLine();
RemoveText();
Console.WriteLine();
ReplaceWithRegex();
Console.WriteLine();
ModifyCharacters();
}
private static void ReplaceText()
{
// <Replace>
string source = "The mountains are behind the clouds today.";
// Replace returns a new string; the original is unchanged.
string updated = source.Replace("mountains", "peaks");
Console.WriteLine(source);
// => The mountains are behind the clouds today.
Console.WriteLine(updated);
// => The peaks are behind the clouds today.
// </Replace>
}
private static void ReplaceCharacters()
{
// <ReplaceChar>
string source = "The mountains are behind the clouds today.";
// Replace every occurrence of one character with another.
string updated = source.Replace(' ', '_');
Console.WriteLine(updated);
// => The_mountains_are_behind_the_clouds_today.
// </ReplaceChar>
}
private static void TrimWhitespace()
{
// <Trim>
string source = " I'm wider than I need to be. ";
// Each method returns a new string with whitespace removed.
Console.WriteLine($"<{source.Trim()}>");
// => <I'm wider than I need to be.>
Console.WriteLine($"<{source.TrimStart()}>");
// => <I'm wider than I need to be. >
Console.WriteLine($"<{source.TrimEnd()}>");
// => < I'm wider than I need to be.>
// </Trim>
}
private static void RemoveText()
{
// <Remove>
string source = "Many mountains are behind many clouds today.";
string toRemove = "many ";
// Find the text, then remove that span by index and length.
int index = source.IndexOf(toRemove);
string result = index >= 0
? source.Remove(index, toRemove.Length)
: source;
Console.WriteLine(result);
// => Many mountains are behind clouds today.
// </Remove>
}
private static void ReplaceWithRegex()
{
// <Regex>
string source = "The mountains are still there behind the clouds today.";
// Replace "the" or "The" followed by whitespace, preserving the original case.
// The \s in the pattern keeps "there" from matching.
string result = Regex.Replace(
source,
"""the\s""",
match => char.IsUpper(match.Value[0]) ? "Many " : "many ",
RegexOptions.IgnoreCase);
Console.WriteLine(result);
// => Many mountains are still there behind many clouds today.
// </Regex>
}
private static void ModifyCharacters()
{
// <CharArray>
string phrase = "The quick brown fox jumps over the fence.";
// A string is immutable, so copy it into a Span<char> to edit in place.
Span<char> characters = stackalloc char[phrase.Length];
phrase.CopyTo(characters);
int index = phrase.IndexOf("fox");
if (index != -1)
{
characters[index] = 'c';
characters[index + 1] = 'a';
characters[index + 2] = 't';
}
// Build a new string from the modified characters.
string updated = new string(characters);
Console.WriteLine(updated);
// => The quick brown cat jumps over the fence.
// </CharArray>
}
}The original string is unchanged, which demonstrates immutability: Replace creates a new string with the substitution.
Replace also has an overload that swaps single characters. The following example replaces every space with an underscore:
sample · csharpdocs/csharp/fundamentals/strings/common-tasks/snippets/modify/Program.csReplaceChar
using System.Text.RegularExpressions;
namespace ModifyStrings;
public static class Program
{
public static void Main()
{
ReplaceText();
Console.WriteLine();
ReplaceCharacters();
Console.WriteLine();
TrimWhitespace();
Console.WriteLine();
RemoveText();
Console.WriteLine();
ReplaceWithRegex();
Console.WriteLine();
ModifyCharacters();
}
private static void ReplaceText()
{
// <Replace>
string source = "The mountains are behind the clouds today.";
// Replace returns a new string; the original is unchanged.
string updated = source.Replace("mountains", "peaks");
Console.WriteLine(source);
// => The mountains are behind the clouds today.
Console.WriteLine(updated);
// => The peaks are behind the clouds today.
// </Replace>
}
private static void ReplaceCharacters()
{
// <ReplaceChar>
string source = "The mountains are behind the clouds today.";
// Replace every occurrence of one character with another.
string updated = source.Replace(' ', '_');
Console.WriteLine(updated);
// => The_mountains_are_behind_the_clouds_today.
// </ReplaceChar>
}
private static void TrimWhitespace()
{
// <Trim>
string source = " I'm wider than I need to be. ";
// Each method returns a new string with whitespace removed.
Console.WriteLine($"<{source.Trim()}>");
// => <I'm wider than I need to be.>
Console.WriteLine($"<{source.TrimStart()}>");
// => <I'm wider than I need to be. >
Console.WriteLine($"<{source.TrimEnd()}>");
// => < I'm wider than I need to be.>
// </Trim>
}
private static void RemoveText()
{
// <Remove>
string source = "Many mountains are behind many clouds today.";
string toRemove = "many ";
// Find the text, then remove that span by index and length.
int index = source.IndexOf(toRemove);
string result = index >= 0
? source.Remove(index, toRemove.Length)
: source;
Console.WriteLine(result);
// => Many mountains are behind clouds today.
// </Remove>
}
private static void ReplaceWithRegex()
{
// <Regex>
string source = "The mountains are still there behind the clouds today.";
// Replace "the" or "The" followed by whitespace, preserving the original case.
// The \s in the pattern keeps "there" from matching.
string result = Regex.Replace(
source,
"""the\s""",
match => char.IsUpper(match.Value[0]) ? "Many " : "many ",
RegexOptions.IgnoreCase);
Console.WriteLine(result);
// => Many mountains are still there behind many clouds today.
// </Regex>
}
private static void ModifyCharacters()
{
// <CharArray>
string phrase = "The quick brown fox jumps over the fence.";
// A string is immutable, so copy it into a Span<char> to edit in place.
Span<char> characters = stackalloc char[phrase.Length];
phrase.CopyTo(characters);
int index = phrase.IndexOf("fox");
if (index != -1)
{
characters[index] = 'c';
characters[index + 1] = 'a';
characters[index + 2] = 't';
}
// Build a new string from the modified characters.
string updated = new string(characters);
Console.WriteLine(updated);
// => The quick brown cat jumps over the fence.
// </CharArray>
}
}Both overloads replace every match in the string, not just the first. Whether you pass a single character or a string, Replace substitutes all occurrences in one call.
Trim whitespace
Use System.String.Trim, System.String.TrimStart, and System.String.TrimEnd to remove leading or trailing whitespace. Each method returns a new string:
sample · csharpdocs/csharp/fundamentals/strings/common-tasks/snippets/modify/Program.csTrim
using System.Text.RegularExpressions;
namespace ModifyStrings;
public static class Program
{
public static void Main()
{
ReplaceText();
Console.WriteLine();
ReplaceCharacters();
Console.WriteLine();
TrimWhitespace();
Console.WriteLine();
RemoveText();
Console.WriteLine();
ReplaceWithRegex();
Console.WriteLine();
ModifyCharacters();
}
private static void ReplaceText()
{
// <Replace>
string source = "The mountains are behind the clouds today.";
// Replace returns a new string; the original is unchanged.
string updated = source.Replace("mountains", "peaks");
Console.WriteLine(source);
// => The mountains are behind the clouds today.
Console.WriteLine(updated);
// => The peaks are behind the clouds today.
// </Replace>
}
private static void ReplaceCharacters()
{
// <ReplaceChar>
string source = "The mountains are behind the clouds today.";
// Replace every occurrence of one character with another.
string updated = source.Replace(' ', '_');
Console.WriteLine(updated);
// => The_mountains_are_behind_the_clouds_today.
// </ReplaceChar>
}
private static void TrimWhitespace()
{
// <Trim>
string source = " I'm wider than I need to be. ";
// Each method returns a new string with whitespace removed.
Console.WriteLine($"<{source.Trim()}>");
// => <I'm wider than I need to be.>
Console.WriteLine($"<{source.TrimStart()}>");
// => <I'm wider than I need to be. >
Console.WriteLine($"<{source.TrimEnd()}>");
// => < I'm wider than I need to be.>
// </Trim>
}
private static void RemoveText()
{
// <Remove>
string source = "Many mountains are behind many clouds today.";
string toRemove = "many ";
// Find the text, then remove that span by index and length.
int index = source.IndexOf(toRemove);
string result = index >= 0
? source.Remove(index, toRemove.Length)
: source;
Console.WriteLine(result);
// => Many mountains are behind clouds today.
// </Remove>
}
private static void ReplaceWithRegex()
{
// <Regex>
string source = "The mountains are still there behind the clouds today.";
// Replace "the" or "The" followed by whitespace, preserving the original case.
// The \s in the pattern keeps "there" from matching.
string result = Regex.Replace(
source,
"""the\s""",
match => char.IsUpper(match.Value[0]) ? "Many " : "many ",
RegexOptions.IgnoreCase);
Console.WriteLine(result);
// => Many mountains are still there behind many clouds today.
// </Regex>
}
private static void ModifyCharacters()
{
// <CharArray>
string phrase = "The quick brown fox jumps over the fence.";
// A string is immutable, so copy it into a Span<char> to edit in place.
Span<char> characters = stackalloc char[phrase.Length];
phrase.CopyTo(characters);
int index = phrase.IndexOf("fox");
if (index != -1)
{
characters[index] = 'c';
characters[index + 1] = 'a';
characters[index + 2] = 't';
}
// Build a new string from the modified characters.
string updated = new string(characters);
Console.WriteLine(updated);
// => The quick brown cat jumps over the fence.
// </CharArray>
}
}Remove a span of characters
The System.String.Remove method deletes a number of characters starting at an index. Combine it with System.String.IndexOf to locate the text to remove:
sample · csharpdocs/csharp/fundamentals/strings/common-tasks/snippets/modify/Program.csRemove
using System.Text.RegularExpressions;
namespace ModifyStrings;
public static class Program
{
public static void Main()
{
ReplaceText();
Console.WriteLine();
ReplaceCharacters();
Console.WriteLine();
TrimWhitespace();
Console.WriteLine();
RemoveText();
Console.WriteLine();
ReplaceWithRegex();
Console.WriteLine();
ModifyCharacters();
}
private static void ReplaceText()
{
// <Replace>
string source = "The mountains are behind the clouds today.";
// Replace returns a new string; the original is unchanged.
string updated = source.Replace("mountains", "peaks");
Console.WriteLine(source);
// => The mountains are behind the clouds today.
Console.WriteLine(updated);
// => The peaks are behind the clouds today.
// </Replace>
}
private static void ReplaceCharacters()
{
// <ReplaceChar>
string source = "The mountains are behind the clouds today.";
// Replace every occurrence of one character with another.
string updated = source.Replace(' ', '_');
Console.WriteLine(updated);
// => The_mountains_are_behind_the_clouds_today.
// </ReplaceChar>
}
private static void TrimWhitespace()
{
// <Trim>
string source = " I'm wider than I need to be. ";
// Each method returns a new string with whitespace removed.
Console.WriteLine($"<{source.Trim()}>");
// => <I'm wider than I need to be.>
Console.WriteLine($"<{source.TrimStart()}>");
// => <I'm wider than I need to be. >
Console.WriteLine($"<{source.TrimEnd()}>");
// => < I'm wider than I need to be.>
// </Trim>
}
private static void RemoveText()
{
// <Remove>
string source = "Many mountains are behind many clouds today.";
string toRemove = "many ";
// Find the text, then remove that span by index and length.
int index = source.IndexOf(toRemove);
string result = index >= 0
? source.Remove(index, toRemove.Length)
: source;
Console.WriteLine(result);
// => Many mountains are behind clouds today.
// </Remove>
}
private static void ReplaceWithRegex()
{
// <Regex>
string source = "The mountains are still there behind the clouds today.";
// Replace "the" or "The" followed by whitespace, preserving the original case.
// The \s in the pattern keeps "there" from matching.
string result = Regex.Replace(
source,
"""the\s""",
match => char.IsUpper(match.Value[0]) ? "Many " : "many ",
RegexOptions.IgnoreCase);
Console.WriteLine(result);
// => Many mountains are still there behind many clouds today.
// </Regex>
}
private static void ModifyCharacters()
{
// <CharArray>
string phrase = "The quick brown fox jumps over the fence.";
// A string is immutable, so copy it into a Span<char> to edit in place.
Span<char> characters = stackalloc char[phrase.Length];
phrase.CopyTo(characters);
int index = phrase.IndexOf("fox");
if (index != -1)
{
characters[index] = 'c';
characters[index + 1] = 'a';
characters[index + 2] = 't';
}
// Build a new string from the modified characters.
string updated = new string(characters);
Console.WriteLine(updated);
// => The quick brown cat jumps over the fence.
// </CharArray>
}
}Replace text that matches a pattern
When you need to replace text that follows a pattern rather than an exact string, use regular expressions. The System.Text.RegularExpressions.Regex.Replace method accepts a function that computes each replacement, so you can preserve details such as the original capitalization. The pattern the\s matches "the" followed by a whitespace character, which prevents it from matching "there":
sample · csharpdocs/csharp/fundamentals/strings/common-tasks/snippets/modify/Program.csRegex
using System.Text.RegularExpressions;
namespace ModifyStrings;
public static class Program
{
public static void Main()
{
ReplaceText();
Console.WriteLine();
ReplaceCharacters();
Console.WriteLine();
TrimWhitespace();
Console.WriteLine();
RemoveText();
Console.WriteLine();
ReplaceWithRegex();
Console.WriteLine();
ModifyCharacters();
}
private static void ReplaceText()
{
// <Replace>
string source = "The mountains are behind the clouds today.";
// Replace returns a new string; the original is unchanged.
string updated = source.Replace("mountains", "peaks");
Console.WriteLine(source);
// => The mountains are behind the clouds today.
Console.WriteLine(updated);
// => The peaks are behind the clouds today.
// </Replace>
}
private static void ReplaceCharacters()
{
// <ReplaceChar>
string source = "The mountains are behind the clouds today.";
// Replace every occurrence of one character with another.
string updated = source.Replace(' ', '_');
Console.WriteLine(updated);
// => The_mountains_are_behind_the_clouds_today.
// </ReplaceChar>
}
private static void TrimWhitespace()
{
// <Trim>
string source = " I'm wider than I need to be. ";
// Each method returns a new string with whitespace removed.
Console.WriteLine($"<{source.Trim()}>");
// => <I'm wider than I need to be.>
Console.WriteLine($"<{source.TrimStart()}>");
// => <I'm wider than I need to be. >
Console.WriteLine($"<{source.TrimEnd()}>");
// => < I'm wider than I need to be.>
// </Trim>
}
private static void RemoveText()
{
// <Remove>
string source = "Many mountains are behind many clouds today.";
string toRemove = "many ";
// Find the text, then remove that span by index and length.
int index = source.IndexOf(toRemove);
string result = index >= 0
? source.Remove(index, toRemove.Length)
: source;
Console.WriteLine(result);
// => Many mountains are behind clouds today.
// </Remove>
}
private static void ReplaceWithRegex()
{
// <Regex>
string source = "The mountains are still there behind the clouds today.";
// Replace "the" or "The" followed by whitespace, preserving the original case.
// The \s in the pattern keeps "there" from matching.
string result = Regex.Replace(
source,
"""the\s""",
match => char.IsUpper(match.Value[0]) ? "Many " : "many ",
RegexOptions.IgnoreCase);
Console.WriteLine(result);
// => Many mountains are still there behind many clouds today.
// </Regex>
}
private static void ModifyCharacters()
{
// <CharArray>
string phrase = "The quick brown fox jumps over the fence.";
// A string is immutable, so copy it into a Span<char> to edit in place.
Span<char> characters = stackalloc char[phrase.Length];
phrase.CopyTo(characters);
int index = phrase.IndexOf("fox");
if (index != -1)
{
characters[index] = 'c';
characters[index + 1] = 'a';
characters[index + 2] = 't';
}
// Build a new string from the modified characters.
string updated = new string(characters);
Console.WriteLine(updated);
// => The quick brown cat jumps over the fence.
// </CharArray>
}
}For pattern-based searching rather than replacement, see Search strings in C#. For the regular expression syntax, see Regular expression language quick reference.
Modify individual characters
To change characters by position, copy the string into a System.Span of characters, modify the span, and then build a new string from it. The following example finds the word "fox" and replaces it with "cat":
sample · csharpdocs/csharp/fundamentals/strings/common-tasks/snippets/modify/Program.csCharArray
using System.Text.RegularExpressions;
namespace ModifyStrings;
public static class Program
{
public static void Main()
{
ReplaceText();
Console.WriteLine();
ReplaceCharacters();
Console.WriteLine();
TrimWhitespace();
Console.WriteLine();
RemoveText();
Console.WriteLine();
ReplaceWithRegex();
Console.WriteLine();
ModifyCharacters();
}
private static void ReplaceText()
{
// <Replace>
string source = "The mountains are behind the clouds today.";
// Replace returns a new string; the original is unchanged.
string updated = source.Replace("mountains", "peaks");
Console.WriteLine(source);
// => The mountains are behind the clouds today.
Console.WriteLine(updated);
// => The peaks are behind the clouds today.
// </Replace>
}
private static void ReplaceCharacters()
{
// <ReplaceChar>
string source = "The mountains are behind the clouds today.";
// Replace every occurrence of one character with another.
string updated = source.Replace(' ', '_');
Console.WriteLine(updated);
// => The_mountains_are_behind_the_clouds_today.
// </ReplaceChar>
}
private static void TrimWhitespace()
{
// <Trim>
string source = " I'm wider than I need to be. ";
// Each method returns a new string with whitespace removed.
Console.WriteLine($"<{source.Trim()}>");
// => <I'm wider than I need to be.>
Console.WriteLine($"<{source.TrimStart()}>");
// => <I'm wider than I need to be. >
Console.WriteLine($"<{source.TrimEnd()}>");
// => < I'm wider than I need to be.>
// </Trim>
}
private static void RemoveText()
{
// <Remove>
string source = "Many mountains are behind many clouds today.";
string toRemove = "many ";
// Find the text, then remove that span by index and length.
int index = source.IndexOf(toRemove);
string result = index >= 0
? source.Remove(index, toRemove.Length)
: source;
Console.WriteLine(result);
// => Many mountains are behind clouds today.
// </Remove>
}
private static void ReplaceWithRegex()
{
// <Regex>
string source = "The mountains are still there behind the clouds today.";
// Replace "the" or "The" followed by whitespace, preserving the original case.
// The \s in the pattern keeps "there" from matching.
string result = Regex.Replace(
source,
"""the\s""",
match => char.IsUpper(match.Value[0]) ? "Many " : "many ",
RegexOptions.IgnoreCase);
Console.WriteLine(result);
// => Many mountains are still there behind many clouds today.
// </Regex>
}
private static void ModifyCharacters()
{
// <CharArray>
string phrase = "The quick brown fox jumps over the fence.";
// A string is immutable, so copy it into a Span<char> to edit in place.
Span<char> characters = stackalloc char[phrase.Length];
phrase.CopyTo(characters);
int index = phrase.IndexOf("fox");
if (index != -1)
{
characters[index] = 'c';
characters[index + 1] = 'a';
characters[index + 2] = 't';
}
// Build a new string from the modified characters.
string updated = new string(characters);
Console.WriteLine(updated);
// => The quick brown cat jumps over the fence.
// </CharArray>
}
}For high-performance scenarios that avoid intermediate allocations, the runtime provides lower-level APIs such as System.String.Create. Those techniques are advanced; for everyday code, the methods in this article are the right choice.