Regular Expressions: A Practical Guide for Developers
Regular expressions (regex) are a powerful pattern-matching language used in every programming language, text editor, and search tool. They can look intimidating, but once you understand the building blocks, you can read and write any regex.
The Building Blocks
Character Classes
| Pattern | Matches |
|---|---|
| . | Any character except newline |
| \d | Digit [0-9] |
| \w | Word character [a-zA-Z0-9_] |
| \s | Whitespace (space, tab, newline) |
| [abc] | Any of a, b, or c |
| [^abc] | Anything except a, b, or c |
Quantifiers
| Pattern | Matches | Type |
|---|---|---|
| * | 0 or more | Greedy |
| + | 1 or more | Greedy |
| ? | 0 or 1 | Greedy |
| {n,m} | Between n and m | Greedy |
| *? | 0 or more | Lazy |
| +? | 1 or more | Lazy |
Groups and References
(abc)— Capturing group (can be referenced as $1 or \1)(?:abc)— Non-capturing group (doesn't create a reference)(?<name>abc)— Named capturing groupabc|def— Alternation (matches abc OR def)
Flags
| Flag | Name | Effect |
|---|---|---|
| g | Global | Find all matches, not just the first |
| i | Case-insensitive | Match regardless of case |
| m | Multiline | ^ and $ match each line, not just the whole string |
| s | Dotall | . matches newlines too |
| u | Unicode | Enable Unicode property escapes (\p{L}) |
| y | Sticky | Match only at lastIndex position |
Common Patterns You'll Use
- Email:
/^[^\s@]+@[^\s@]+\.[^\s@]+$/ - URL:
/https?:\/\/(www\.)?[\w-]+\.[\w]{2,}(\/[\w-]*)*$/ - Phone (US):
/\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}/ - IPv4:
/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/ - Date (YYYY-MM-DD):
/\d{4}-\d{2}-\d{2}/
Test your Regex Live
Use our Regex Tester & Highlighter to test any pattern with real-time match highlighting, capture group display, and all flag support.
Worked Example: Building a Log Timestamp Pattern from Scratch
Goal: extract timestamps like 2026-06-13 14:03:22 from an application log. Build the pattern incrementally:
- Year: four digits →
\d{4}matches2026 - Separator: a literal hyphen (safe outside character classes, no escape needed)
- Month and day: two digits each →
\d{2} - Repeat for the time part with colons:
\d{2}:\d{2}:\d{2} - Anchor the whole thing:
^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$
Then test against real lines:
| Input line | Matches? |
|---|---|
| 2026-06-13 14:03:22 INFO User logged in | Yes, once the ^ and $ anchors are removed |
| 2026-6-3 9:03:22 | No — single digits fail \d{2} |
| 2026-13-45 25:99:99 | Yes — the shape matches, but it is not a valid date |
The last row teaches the key lesson: regex validates shape, not semantics. If invalid dates must be rejected, add range checks like (0[1-9]|1[0-2]) for months, or validate in code after the match. Test each iteration live in the Regex Tester & Highlighter before moving on.
Common Mistakes
- Forgetting the g flag — without it a regex matches only the first occurrence, so
"a1b1".match(/\d/)returns just1. This causes most "my regex is broken" reports. - Trusting greedy quantifiers —
<.*>on<a>text</b>swallows the entire string. Use lazy<.*?>or, better, a negated class like[^<]*. - Escaping more than needed — inside a character class,
[.]matches a literal dot, but a bare.outside a class means "any character." Know which context you are in. - Using regex to parse structured formats — HTML, JSON, and CSV all have grammars regex cannot fully express. Extract simple patterns with regex; parse real formats with real parsers.
- Writing patterns nobody can read — a 200-character regex with no examples is unmaintainable. Use named groups, keep a comment with three matching sample strings, and prefer several simple patterns over one clever monster.
Frequently Asked Questions
Why does my regex work in one language but not another?
Flavors differ: old JavaScript engines lack lookbehind, POSIX tools like grep treat shorthand differently, and Unicode handling varies. Write the pattern against the flavor of your runtime, then test it in that exact environment.
What is the difference between (?:...) and (...)?
(...) captures the matched text so you can reference it in a replacement or match object; (?:...) groups without capturing. If you never use the group, make it non-capturing — it keeps group numbering clean and is marginally faster.
How do I match anything including newlines?
Either enable the s (dotall) flag so . matches newlines, or use the explicit class [\s\S], which works in every flavor regardless of flags. The latter is the portable choice.
Can regex be dangerous for performance?
Yes. Nested quantifiers like (a+)+$ can trigger catastrophic backtracking, freezing the thread on adversarial input. Avoid stacking quantifiers over quantifiers, and test any user-supplied pattern against a pathological string before shipping it.
The Bottom Line
- Regex is built from character classes, quantifiers, groups, and anchors
- Use lazy quantifiers (*? +?) to avoid over-matching
- Named groups (
?<name>) make complex regex readable - Always test with edge cases — regex bugs are subtle
- For complex parsing (HTML, CSV), use a proper parser, not regex
Disclaimer: This guide is for informational purposes only. Regex implementations vary slightly between languages — always test in your target environment.
Related Free Tools
Put this guide into practice with our free browser-based tools — no signup, no upload, 100% local processing.