Regex in C#
C# regular expressions are handled by the System.Text.RegularExpressions namespace. The Regex class provides static and instance methods for matching, replacing, and splitting strings. The .NET regex engine supports lookaround, named capture groups, atomic groups, balancing groups, and compiled patterns for high-performance reuse.
Code Examples
Check if a string matches a pattern
using System.Text.RegularExpressions;
// Static method — no Regex instance needed
bool isEmail = Regex.IsMatch(
"user@example.com",
@"^[w.+-]+@[w-]+.[w.]+$",
RegexOptions.IgnoreCase
);
Console.WriteLine(isEmail); // TrueRegex.IsMatch() is the fastest way to do a boolean check. Use the verbatim string literal (@"...") to avoid double-escaping backslashes — \\d becomes \d.
Extract the first match and capture groups
using System.Text.RegularExpressions;
string text = "Invoice #INV-2026-0042 dated 2026-03-15";
Match m = Regex.Match(text, @"#(INV-d{4}-d{4})");
if (m.Success) {
Console.WriteLine(m.Value); // "#INV-2026-0042"
Console.WriteLine(m.Groups[1].Value); // "INV-2026-0042"
}Match.Success is true when the pattern matched. m.Value is the full match; m.Groups[1] is the first capture group. Groups[0] always equals the full match.
Find all matches
using System.Text.RegularExpressions;
string prices = "Cart: $12.99, $5.50, $120.00";
MatchCollection matches = Regex.Matches(prices, @"$(d+.d{2})");
foreach (Match m in matches) {
Console.WriteLine($"{m.Value} => amount: {m.Groups[1].Value}");
}
// $12.99 => amount: 12.99
// $5.50 => amount: 5.50
// $120.00 => amount: 120.00Regex.Matches() returns a MatchCollection of all non-overlapping matches. Iterate with foreach — each Match has the same Groups API as a single Match.
Named capture groups
using System.Text.RegularExpressions;
string date = "2026-03-15";
Match m = Regex.Match(date, @"(?<year>d{4})-(?<month>d{2})-(?<day>d{2})");
if (m.Success) {
Console.WriteLine(m.Groups["year"].Value); // "2026"
Console.WriteLine(m.Groups["month"].Value); // "03"
Console.WriteLine(m.Groups["day"].Value); // "15"
}Named groups use (?<name>...) syntax. Access them by name via m.Groups["name"].Value. Named groups also get a numeric index, so you can use both styles.
Search and replace
using System.Text.RegularExpressions;
// Static replacement with backreferences ($1, $2)
string swapped = Regex.Replace("John Smith", @"(w+)s(w+)", "$2, $1");
Console.WriteLine(swapped); // "Smith, John"
// Dynamic replacement with MatchEvaluator
string result = Regex.Replace(
"hello world",
@"[a-z]",
m => m.Value.ToUpper()
);
Console.WriteLine(result); // "Hello World"Regex.Replace() accepts either a replacement string (with $1/$2 or ${name} backreferences) or a MatchEvaluator delegate for dynamic replacements. The MatchEvaluator receives each Match and returns the replacement string.
Compiled Regex for performance
using System.Text.RegularExpressions;
// Compile once at startup — faster for repeated use
private static readonly Regex _slugRegex = new Regex(
@"[^a-z0-9]+",
RegexOptions.Compiled | RegexOptions.IgnoreCase
);
public static string ToSlug(string input) {
return _slugRegex.Replace(input.Trim(), "-").ToLower();
}RegexOptions.Compiled generates IL code for the pattern, reducing per-call overhead by ~10x at the cost of a one-time compilation delay. Use it for patterns that run thousands of times. Store as static readonly to compile only once.
Note
Always use verbatim string literals (@"pattern") for regex patterns in C# to avoid double-escaping backslashes. Common RegexOptions: IgnoreCase (i), Multiline (^ and $ match line boundaries), Singleline (dot matches newline), IgnorePatternWhitespace (verbose mode), Compiled (faster repeated calls). In .NET 7+, the source generator Regex.IsMatch partial methods give compile-time–verified patterns with zero runtime compilation overhead.
Regex in Other Languages
Frequently Asked Questions
What is the difference between Regex.Match() and Regex.Matches()?
Regex.Match() returns the first match only (a single Match object). Regex.Matches() returns all non-overlapping matches as a MatchCollection. Always check Match.Success before using Match.Value when using Match().
How do I use case-insensitive matching in C#?
Pass RegexOptions.IgnoreCase as the third argument: Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase). For inline flags, use (?i) at the start of the pattern: Regex.Match(input, @"(?i)hello").
How do I enable multiline mode in C# regex?
Use RegexOptions.Multiline so ^ and $ match the start and end of each line (not just the whole string). For dot-matches-newline behaviour, use RegexOptions.Singleline instead. You can combine flags: RegexOptions.Multiline | RegexOptions.IgnoreCase.
What are balancing groups in .NET regex?
Balancing groups ((?<open>...) paired with (?<-open>...)) are a .NET-specific feature that lets you match nested structures like balanced parentheses or HTML tags. They push/pop a stack for the named group, so a final (?(open)(?!)) assertion can verify the stack is empty at the end of the match.
Want to test a C# regex pattern? Our regex tester runs JavaScript's native RegExp engine in your browser — paste your pattern and see matches in real time.
← Open the Regex Tester