C# Regex — pattern matching, groups, replace, and examples
The System.Text.RegularExpressions.Regex class gives you pattern-based string searching, validation, extraction, and replacement. For simple substring checks use string.Contains — reach for Regex when the pattern is dynamic or too complex to express with plain string methods.
using System.Text.RegularExpressions;IsMatch — Test Whether a Pattern Exists
// Validate an email address (simplified pattern)
string email = "alice@example.com";
bool isValid = Regex.IsMatch(email, @"^[^@\s]+@[^@\s]+\.[^@\s]+$");
Console.WriteLine(isValid); // True
// Check for digits
bool hasDigits = Regex.IsMatch("abc123", @"\d");
Console.WriteLine(hasDigits); // True
bool noDigits = Regex.IsMatch("abcdef", @"\d");
Console.WriteLine(noDigits); // FalseThe @ prefix on the string literal avoids double-escaping backslashes (\d instead of \\d).
Match — Extract the First Match
string log = "Error at 2024-03-15 14:32:01: connection refused";
Match match = Regex.Match(log, @"\d{4}-\d{2}-\d{2}");
if (match.Success)
Console.WriteLine($"Date found: {match.Value}"); // Date found: 2024-03-15Matches — Extract All Matches
string text = "Call us at 555-1234 or 555-5678 between 9am and 5pm.";
MatchCollection matches = Regex.Matches(text, @"\d{3}-\d{4}");
foreach (Match m in matches)
Console.WriteLine(m.Value);
// 555-1234
// 555-5678Capture Groups
Wrap part of a pattern in (...) to capture it separately from the full match.
string date = "2024-03-15";
Match m = Regex.Match(date, @"(\d{4})-(\d{2})-(\d{2})");
if (m.Success)
{
Console.WriteLine($"Year: {m.Groups[1].Value}"); // 2024
Console.WriteLine($"Month: {m.Groups[2].Value}"); // 03
Console.WriteLine($"Day: {m.Groups[3].Value}"); // 15
}Named Capture Groups
Use (?<name>...) to give groups readable names instead of indices.
string input = "John Smith, age 42";
Match m = Regex.Match(input, @"(?<first>\w+)\s(?<last>\w+),\sage\s(?<age>\d+)");
if (m.Success)
{
Console.WriteLine(m.Groups["first"].Value); // John
Console.WriteLine(m.Groups["last"].Value); // Smith
Console.WriteLine(m.Groups["age"].Value); // 42
}Replace — Substitute Matches
// Redact credit card numbers (replace all but last 4 digits)
string text = "Card: 4111-1111-1111-1234";
string redacted = Regex.Replace(text, @"\d{4}-\d{4}-\d{4}-", "****-****-****-");
Console.WriteLine(redacted); // Card: ****-****-****-1234
// Normalize whitespace — collapse multiple spaces into one
string messy = "This has extra spaces";
string clean = Regex.Replace(messy, @"\s+", " ");
Console.WriteLine(clean); // This has extra spaces
// Replace using a MatchEvaluator (transform each match)
string result = Regex.Replace("hello world", @"\b\w", m => m.Value.ToUpper());
Console.WriteLine(result); // Hello WorldSplit
// Split on any whitespace or comma
string csv = "alpha, beta, gamma ,delta";
string[] parts = Regex.Split(csv, @"\s*,\s*");
foreach (var p in parts)
Console.WriteLine($"'{p}'");
// 'alpha'
// 'beta'
// 'gamma'
// 'delta'RegexOptions
// Case-insensitive match
bool found = Regex.IsMatch("Hello World", @"hello", RegexOptions.IgnoreCase);
Console.WriteLine(found); // True
// Multiline — ^ and $ match start/end of each line, not the whole string
string multiline = "line one\nline two\nline three";
MatchCollection lineStarts = Regex.Matches(multiline, @"^line", RegexOptions.Multiline);
Console.WriteLine(lineStarts.Count); // 3
// Combine with bitwise OR
var options = RegexOptions.IgnoreCase | RegexOptions.Multiline;| Option | Effect |
|---|---|
IgnoreCase | Case-insensitive matching |
Multiline | ^/$ match line boundaries, not string boundaries |
Singleline | . matches newlines too |
IgnorePatternWhitespace | Allows comments and whitespace inside pattern |
Compiled | Compiles to IL — faster repeated use, slower first call |
Compiled Regex — for Repeated Use
When you call the same pattern thousands of times, create a compiled Regex instance. The static Regex.IsMatch(...) overload re-parses the pattern each call.
// Create once (e.g., as a static field)
private static readonly Regex EmailRegex = new(
@"^[^@\s]+@[^@\s]+\.[^@\s]+$",
RegexOptions.Compiled | RegexOptions.IgnoreCase
);
// Reuse many times — no re-parsing overhead
bool IsValidEmail(string input) => EmailRegex.IsMatch(input);Source Generators (C# 11+ / .NET 7+)
Use [GeneratedRegex] to generate the regex at compile time — zero runtime compilation overhead and AOT-friendly.
using System.Text.RegularExpressions;
public partial class Validator
{
[GeneratedRegex(@"^[^@\s]+@[^@\s]+\.[^@\s]+$", RegexOptions.IgnoreCase)]
private static partial Regex EmailRegex();
public static bool IsValidEmail(string input) => EmailRegex().IsMatch(input);
}Common Regex Patterns
| Purpose | Pattern |
|---|---|
| Integer | ^-?\d+$ |
| Decimal number | ^-?\d+(\.\d+)?$ |
| Email (basic) | ^[^@\s]+@[^@\s]+\.[^@\s]+$ |
| URL | ^https?://[^\s/$.?#].[^\s]*$ |
| Date (yyyy-MM-dd) | ^\d{4}-\d{2}-\d{2}$ |
| Phone (US) | ^\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$ |
| Whitespace-only | ^\s*$ |
| Hex color | ^#[0-9A-Fa-f]{6}$ |
Regex vs String Methods
| Need | Prefer |
|---|---|
| Check substring exists | string.Contains() |
| Check start/end | string.StartsWith() / EndsWith() |
| Simple replace | string.Replace() |
| Complex pattern match | Regex |
| Validation with a pattern | Regex.IsMatch() |
| Extract structured data | Regex + groups |