8.6. Regular Expressions#

Regular expressions (regex) are patterns that describe text. They extend the string search and replace operations from the previous section, letting you match flexible, structured patterns instead of exact strings.

Regex lives in the System.Text.RegularExpressions namespace.

using System.Text.RegularExpressions;

8.6.1. Checking for a Match#

Regex.IsMatch returns true if the pattern appears anywhere in the string:

// Does the string contain any digit?
bool hasDigit = Regex.IsMatch("Score: 98", @"\d");
Console.WriteLine(hasDigit);  // True

// Does it start with a capital letter?
bool startsUpper = Regex.IsMatch("Alice", @"^[A-Z]");
Console.WriteLine(startsUpper);  // True

8.6.2. Common Pattern Elements#

Pattern

Meaning

Example match

\d

any digit

7, 0

\w

word character (letter, digit, _)

a, Z, 3

\s

whitespace

space, tab

.

any character except newline

x, !

^

start of string

^Hello matches Hello world

$

end of string

\.txt$ matches file.txt

[abc]

one of a, b, c

[aeiou] matches any vowel

[A-Z]

range

any uppercase letter

+

one or more

\d+ matches 42

*

zero or more

\d* matches `` or 99

?

zero or one

colou?r matches color or colour

8.6.3. Extracting a Match#

Regex.Match returns the first match object:

string line = "Student: Alice, Score: 98";
Match m = Regex.Match(line, @"\d+");

if (m.Success)
    Console.WriteLine($"First number found: {m.Value}");  // 98

8.6.4. Finding All Matches#

Regex.Matches returns every match:

string data = "Scores: 85, 92, 78, 90";
MatchCollection matches = Regex.Matches(data, @"\d+");

foreach (Match m in matches)
    Console.WriteLine(m.Value);
// 85  92  78  90

8.6.5. Replacing with a Pattern#

Regex.Replace substitutes every match:

// Normalize multiple spaces to one
string messy = "Alice,  98,   CS";
string clean = Regex.Replace(messy, @"\s{2,}", " ");
Console.WriteLine(clean);  // Alice,  98,   CS -> "Alice, 98, CS"
// Remove all non-digit characters
string phone = "(312) 555-0190";
string digits = Regex.Replace(phone, @"[^\d]", "");
Console.WriteLine(digits);  // 3125550190

8.6.6. Using Groups to Extract Fields#

Parentheses create capture groups — named parts of a match:

string record = "Alice,98,CS";
Match m = Regex.Match(record, @"^(?<name>\w+),(?<score>\d+),(?<major>\w+)$");

if (m.Success)
{
    Console.WriteLine($"Name:  {m.Groups["name"].Value}");
    Console.WriteLine($"Score: {m.Groups["score"].Value}");
    Console.WriteLine($"Major: {m.Groups["major"].Value}");
}

8.6.7. Validation Patterns#

Common tasks well-suited to regex:

// Simple email check (not exhaustive)
bool isEmail = Regex.IsMatch("user@example.com", @"^[\w.+-]+@[\w-]+\.[a-z]{2,}$");
Console.WriteLine($"valid email: {isEmail}");

// Zip code (5 digits)
bool isZip = Regex.IsMatch("60660", @"^\d{5}$");
Console.WriteLine($"valid zip: {isZip}");

// Date format YYYY-MM-DD
bool isDate = Regex.IsMatch("2026-03-17", @"^\d{4}-\d{2}-\d{2}$");
Console.WriteLine($"valid date: {isDate}");

8.6.8. When to Use Regex vs. String Methods#

Use string methods

Use regex

Exact match or replace

Pattern-based match

Fixed delimiter Split(',')

Variable whitespace or delimiters

Contains, StartsWith

Character classes, repetition

Performance-critical loops

One-time validation or extraction

Regex adds power but also complexity — prefer Split, Trim, and Contains when the pattern is simple and fixed.

8.6.9. Practice#

  1. Write a pattern to match a C# int or double literal (e.g. 42, -3, 3.14).

  2. Extract all words (sequences of \w+) from a sentence and print each on its own line.

  3. Validate that a filename ends with .cs or .txt.

  4. Replace all tab characters in a file line with four spaces.

Footnotes