Skip to main content

Mastering Regular Expression. Part 9: Regex Anti-Patterns & Common Mistakes in C#

Regular Expressions are powerful — but with great power comes great potential for bugs, performance issues, and maintenance nightmares. In this part, you’ll learn how to avoid traps and write smarter, safer regex in C#.


9.1 Catastrophic Backtracking

❌ Problem:

Poorly written patterns with nested quantifiers can take exponential time.

Example:

var pattern = @"^(a+)+$";
var input = new string('a', 10000) + "!";
Regex.IsMatch(input, pattern); // ❗ Will hang or be super slow

✅ Solution:

Use atomic groups or lazy quantifiers. Or redesign.

var safePattern = @"^a+$";

Avoid unbounded nested quantifiers like (a+)+, (.*)+, (.+)+.


9.2 Greedy vs Lazy Quantifiers

❌ Greedy Example:

var input = "<tag>Hello</tag><tag>World</tag>";
var pattern = "<tag>.*</tag>";
var matches = Regex.Matches(input, pattern); // Returns one big match

✅ Lazy (non-greedy):

var pattern = "<tag>.*?</tag>";

Greedy * or + can swallow more than intended. Use *?, +? when needed.


9.3 Overusing Regex When Simpler Code Works

❌ Bad:

var input = "John,Doe,35,USA";
var parts = Regex.Split(input, ",");

✅ Good:

var parts = input.Split(',');

Regex should be used when pattern-matching is needed — not for basic splitting or trimming.


9.4 Unreadable Patterns

❌ Bad:

var pattern = @"^([A-Z]{3})([0-9]{2,4})([a-z]{1,3})$";

Hard to maintain or explain.

✅ Good:

Use named groups and comments:

var pattern = @"
^
(?<Prefix>[A-Z]{3})
(?<Code>[0-9]{2,4})
(?<Suffix>[a-z]{1,3})
$";

Regex.Match(input, pattern, RegexOptions.IgnorePatternWhitespace);

Named groups and comments make regex maintainable.


9.5 Too Many Capture Groups

❌ Bad:

var pattern = @"(\d{4})-(\d{2})-(\d{2})";

Accessing groups by number is fragile.

✅ Better:

var pattern = @"(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})";
var match = Regex.Match(input, pattern);
Console.WriteLine(match.Groups["month"].Value);

Always use named groups when possible.


9.6 Not Escaping Special Characters

❌ Broken pattern:

var pattern = @"C:\Users\John\Documents";

\U, \J, etc., are invalid escape sequences.

✅ Fix:

var pattern = @"C:\\Users\\John\\Documents";

Escape backslashes \\, dots \., brackets \[ etc.


9.7 Forgetting to Escape User Input in Dynamic Regex

❌ Injection Risk:

var search = ".*"; // From user
var pattern = $"^{search}$"; // Becomes dangerous

✅ Escape Input:

var safe = Regex.Escape(search);
var pattern = $"^{safe}$";

Always sanitize dynamic regex input using Regex.Escape().


9.8 Assuming Match Always Succeeds

❌ Crash:

var match = Regex.Match(input, pattern);
Console.WriteLine(match.Groups[1].Value); // Throws if no match

✅ Check first:

if (match.Success) {
    Console.WriteLine(match.Groups[1].Value);
}

Always check match.Success before accessing groups.


9.9 Mixing RegexOptions Improperly

❌ Ignored pattern:

var pattern = @"(?x) A #comment";
Regex.IsMatch("A", pattern); // Doesn't work in C#

Inline options like (?x) are not always supported in all places.

✅ Better:

Regex.IsMatch("A", @"A", RegexOptions.IgnorePatternWhitespace);

Use RegexOptions enums in C# instead of inline flags when possible.


9.10 Over-Compiling Regex

❌ Overkill:

var regex = new Regex(pattern, RegexOptions.Compiled); // Every time

This can slow down startup and bloat memory for many one-off patterns.

✅ When to use Compiled:

  • When the regex is used thousands of times per second
  • When performance is critical

For occasional matches, skip RegexOptions.Compiled.


Summary Checklist

✅ Avoid nested quantifiers like (a+)+
✅ Use lazy quantifiers when needed
✅ Prefer Split() over regex unless necessary
✅ Use named groups
✅ Escape dynamic inputs with Regex.Escape()
✅ Handle failures (match.Success)
✅ Benchmark performance
✅ Avoid premature Compiled
✅ Use RegexOptions for clarity
✅ Write maintainable, readable regex


🔜 Coming Up Next

In Part 10, we’ll go even deeper into building custom regex engines, explore RegexCompilationInfo, and experiment with code generation for regex classes.

Comments

Popular posts from this blog