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.RegularExpressionsnamespace.
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 |
|---|---|---|
|
any digit |
|
|
word character (letter, digit, |
|
|
whitespace |
space, tab |
|
any character except newline |
|
|
start of string |
|
|
end of string |
|
|
one of a, b, c |
|
|
range |
any uppercase letter |
|
one or more |
|
|
zero or more |
|
|
zero or one |
|
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 |
Use regex |
|---|---|
Exact match or replace |
Pattern-based match |
Fixed delimiter |
Variable whitespace or delimiters |
|
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#
Write a pattern to match a C#
intordoubleliteral (e.g.42,-3,3.14).Extract all words (sequences of
\w+) from a sentence and print each on its own line.Validate that a filename ends with
.csor.txt.Replace all tab characters in a file line with four spaces.
Footnotes