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.

C# Example Code
using System.Text.RegularExpressions;

IsMatch — Test Whether a Pattern Exists

C# Example Code
// 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); // False

The @ prefix on the string literal avoids double-escaping backslashes (\d instead of \\d).

Match — Extract the First Match

C# Example Code
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-15

Matches — Extract All Matches

C# Example Code
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-5678

Capture Groups

Wrap part of a pattern in (...) to capture it separately from the full match.

C# Example Code
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.

C# Example Code
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

C# Example Code
// 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 World

Split

C# Example Code
// 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

C# Example Code
// 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;
OptionEffect
IgnoreCaseCase-insensitive matching
Multiline^/$ match line boundaries, not string boundaries
Singleline. matches newlines too
IgnorePatternWhitespaceAllows comments and whitespace inside pattern
CompiledCompiles 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.

C# Example Code
// 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.

C# Example Code
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

PurposePattern
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

NeedPrefer
Check substring existsstring.Contains()
Check start/endstring.StartsWith() / EndsWith()
Simple replacestring.Replace()
Complex pattern matchRegex
Validation with a patternRegex.IsMatch()
Extract structured dataRegex + groups