Skip to content

C# - Regular Expressions

A regular expression (or regex) is a sequence of characters that defines a search pattern. In C#, the System.Text.RegularExpressions namespace provides a powerful engine for pattern matching, validation, replacement, and splitting of strings.

A regex pattern is built from literals (like a, b, 1) and metacharacters, which have special meanings.

CategoryConstructDescriptionExample
Character Classes.Matches any single character except newline.h.t matches ‘hat’, ‘hot’, ‘h&t’
\dMatches any digit (0-9). \D matches non-digits.\d{3} matches ‘123’
\wMatches any word character (a-z, A-Z, 0-9, _). \W matches non-word characters.\w+ matches ‘hello_123’
\sMatches any whitespace character. \S matches non-whitespace.hello\sworld
[...]Matches any single character in the set.[aeiou] matches any vowel
Anchors^Matches the start of the string.^Hello
$Matches the end of the string.world$
\bMatches a word boundary.\bcat\b matches ‘cat’, not ‘category’
Quantifiers*Zero or more occurrences.a* matches ”, ‘a’, ‘aa’
+One or more occurrences.a+ matches ‘a’, ‘aa’
?Zero or one occurrence.colou?r matches ‘color’ and ‘colour’
{n}Exactly n occurrences.\d{4} matches a 4-digit number

Note: In C# strings, the backslash \ is an escape character. To write a literal backslash for your regex pattern, you must either escape it ("\\d") or use a verbatim string literal (@"\d"). The verbatim syntax is strongly recommended for readability.

The static methods on the Regex class are convenient for one-off uses, while creating a Regex instance is more efficient if you use the same pattern multiple times.

  • Regex.IsMatch(input, pattern): Returns true if the pattern finds a match in the input.
  • Regex.Match(input, pattern): Returns a Match object for the first match found.
  • Regex.Matches(input, pattern): Returns a MatchCollection of all matches found.
  • Regex.Replace(input, pattern, replacement): Replaces all matches with a replacement string.
  • Regex.Split(input, pattern): Splits the input string at each match.

Let’s check if a string matches a simple North American phone number format like XXX-XXX-XXXX.

using System.Text.RegularExpressions;
string[] phoneNumbers = { "123-456-7890", "123 456 7890", "999-999-999" };
string pattern = @"^\d{3}-\d{3}-\d{4}$";
foreach (var number in phoneNumbers)
{
bool isValid = Regex.IsMatch(number, pattern);
Console.WriteLine($"'{number}' is a valid format: {isValid}");
}
// Output:
// '{number}' is a valid format: True
// '{number}' is a valid format: False
// '{number}' is a valid format: False

Example: Extracting All Hashtags from Text

Section titled “Example: Extracting All Hashtags from Text”

Here, we’ll instantiate a Regex object to find all words that start with a #.

using System.Text.RegularExpressions;
string text = "Check out this #cool #feature in #CSharp! It's #awesome.";
string pattern = @"#\w+";
Regex hashtagRegex = new Regex(pattern);
MatchCollection matches = hashtagRegex.Matches(text);
Console.WriteLine($"Found {matches.Count} hashtags:");
foreach (Match match in matches)
{
Console.WriteLine(match.Value);
}
// Output:
// Found 3 hashtags:
// #cool
// #feature
// #CSharp
// #awesome

The Replace method is useful for cleaning up user input.

using System.Text.RegularExpressions;
string messyInput = "This string has too much space.";
string pattern = @"\s+";
string replacement = " ";
string cleanOutput = Regex.Replace(messyInput, pattern, replacement);
Console.WriteLine($"Original: '{messyInput}'");
Console.WriteLine($"Cleaned: '{cleanOutput}'");
// Output:
// Original: 'This string has too much space.'
// Cleaned: 'This string has too much space.'

For performance-critical applications, .NET 7 introduced the Regex Source Generator. By decorating a partial method with the [GeneratedRegex] attribute, the compiler pre-processes your pattern at build time, generating highly optimized code. This avoids the runtime overhead of parsing the pattern and is the recommended approach for modern C#.

To use this, your containing class must be partial.

using System.Text.RegularExpressions;
public partial class MyValidators
{
// The source generator creates the implementation of this method at compile time.
[GeneratedRegex(@"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$", RegexOptions.IgnoreCase)]
public static partial Regex EmailRegex();
}
// --- Usage ---
string email = "test@example.com";
if (MyValidators.EmailRegex().IsMatch(email))
{
Console.WriteLine("Email is valid.");
} else {
Console.WriteLine("Email is invalid.");
}
// Note: The provided email regex is for demonstration.
// Perfect email validation is notoriously complex.

Using the source generator gives you the performance of a compiled, cached Regex instance with the simple syntax of a static method call.