How to Test Regex Patterns: A Developer Guide
Learn how to test regular expressions effectively, match groups, flags, and common patterns. Includes JavaScript, Python, and online testing tools.
Regular expressions (regex) are powerful but notoriously tricky. A pattern that looks correct can silently fail on edge cases, or worse, cause catastrophic backtracking that freezes your application. Testing regex properly is essential.
Why Regex Testing Matters
A regex that works on your test string might fail on real-world input. Consider a simple email regex: ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$. It passes basic tests but fails on addresses like user+tag@sub.domain.co.uk or name@192.168.1.1.
Testing means checking:
- Does it match what it should?
- Does it NOT match what it shouldn't?
- Are capture groups extracting the right data?
- How does it handle edge cases (empty strings, Unicode, very long inputs)?
Regex Fundamentals
Basic Syntax
| Pattern | Matches |
|---------|---------|
| abc | Literal string "abc" |
| . | Any single character |
| \d | Digit (0-9) |
| \w | Word character (a-z, A-Z, 0-9, _) |
| \s | Whitespace |
| ^ | Start of string |
| $ | End of string |
| * | Zero or more |
| + | One or more |
| ? | Zero or one |
| {n,m} | Between n and m times |
Capture Groups
Parentheses create capture groups:
const match = "2026-09-19".match(/(\d{4})-(\d{2})-(\d{2})/);
// match[1] = "2026" (year)
// match[2] = "09" (month)
// match[3] = "19" (day)
Named groups are more readable:
const match = "2026-09-19".match(/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/);
// match.groups.year = "2026"
Flags
| Flag | Name | Effect |
|------|------|--------|
| g | Global | Find all matches, not just the first |
| i | Case-insensitive | Ignore case when matching |
| m | Multiline | ^ and $ match line starts/ends |
| s | Dotall | . matches newlines |
Testing Strategies
1. Test Positive Cases (Should Match)
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
// These should all return true
emailRegex.test("user@example.com"); // true
emailRegex.test("name@domain.co.uk"); // true
emailRegex.test("user+tag@example.org"); // true
2. Test Negative Cases (Should NOT Match)
// These should all return false
emailRegex.test(""); // false
emailRegex.test("not-email"); // false
emailRegex.test("@no-user.com"); // false
emailRegex.test("user@"); // false
3. Test Edge Cases
// Unicode
emailRegex.test("usér@example.com"); // depends on your regex
// Very long input
emailRegex.test("a".repeat(100) + "@example.com");
// Special characters
emailRegex.test("user@sub.domain.co.uk");
4. Verify Capture Groups
const urlRegex = /^(?<protocol>https?):\/\/(?<host>[^/]+)(?<path>\/.*)?$/;
const match = urlRegex.exec("https://example.com/path?q=1");
console.log(match.groups.protocol); // "https"
console.log(match.groups.host); // "example.com"
console.log(match.groups.path); // "/path?q=1"
Common Regex Patterns
Email (Simple)
^[^\s@]+@[^\s@]+\.[^\s@]+$
URL
^https?:\/\/[^\s/$.?#].[^\s]*$
Phone Number (US)
^\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}$
IP Address (v4)
^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$
Date (YYYY-MM-DD)
^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$
Performance Pitfalls
Catastrophic Backtracking
Avoid nested quantifiers:
# BAD — can cause exponential backtracking
^(a+)+$
# GOOD — same match, no backtracking risk
^a+$
Greedy vs Lazy
Greedy (*, +) matches as much as possible. Lazy (*?, +?) matches as little as possible.
"<div>content</div>".match(/<div>(.*)<\/div>/); // greedy: matches whole string
"<div>content</div>".match(/<div>(.*?)<\/div>/); // lazy: matches "content"
Try It Now
Use our free Regex Tester to test patterns in real-time — with match highlighting, group extraction, and a library of common patterns.