A Practical Guide to Regular Expressions for Developers
March 20, 2026 · 8 min read
Regular expressions are one of those tools that feel arcane at first but become indispensable once you know them. This guide skips the theory and focuses on the patterns you'll actually use — with working examples you can test right now.
The Basics: Literals and Metacharacters
At its simplest, a regex is just a string to search for. The pattern hello matches the literal text "hello" anywhere in a string. The power comes from metacharacters — special characters with meaning:
| Character | Meaning |
|---|---|
| . | Any single character (except newline) |
| ^ | Start of string |
| $ | End of string |
| * | 0 or more of the preceding |
| + | 1 or more of the preceding |
| ? | 0 or 1 of the preceding (optional) |
| | | Or (alternation) |
| \\ | Escape a metacharacter |
Character Classes
Square brackets define a set of characters to match. Only one character from the set matches at that position.
| Pattern | Matches |
|---|---|
| [abc] | 'a', 'b', or 'c' |
| [^abc] | Any character except 'a', 'b', 'c' |
| [a-z] | Any lowercase letter |
| [A-Z] | Any uppercase letter |
| [0-9] | Any digit |
| \d | Any digit (shorthand for [0-9]) |
| \w | Word character [a-zA-Z0-9_] |
| \s | Whitespace (space, tab, newline) |
| \D | Non-digit |
| \W | Non-word character |
| \S | Non-whitespace |
Quantifiers
| Quantifier | Meaning |
|---|---|
| {n} | Exactly n times |
| {n,} | n or more times |
| {n,m} | Between n and m times |
| * | 0 or more (greedy) |
| + | 1 or more (greedy) |
| *? | 0 or more (lazy — match as few as possible) |
| +? | 1 or more (lazy) |
Groups and Capturing
Parentheses create groups. Groups let you capture parts of a match and apply quantifiers to multiple characters at once.
// Capturing group — captures "2024" from "2024-03-31"
(d{4})-d{2}-d{2}
// Non-capturing group — groups without capturing
(?:d{4})-d{2}-d{2}
// Named capturing group
(?<year>d{4})-(?<month>d{2})-(?<day>d{2})In JavaScript, named groups are accessed via match.groups.year.
Lookaheads and Lookbehinds
Lookarounds assert what comes before or after a position without consuming characters.
| Syntax | Type |
|---|---|
| x(?=y) | x followed by y (positive lookahead) |
| x(?!y) | x not followed by y (negative lookahead) |
| (?<=y)x | x preceded by y (positive lookbehind) |
| (?<!y)x | x not preceded by y (negative lookbehind) |
Real-World Patterns
Email address (simplified)
^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$URL
https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}([-a-zA-Z0-9()@:%_+.~#?&/=]*)ISO date (YYYY-MM-DD)
^d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]d|3[01])$IPv4 address
^((25[0-5]|2[0-4]d|[01]?dd?).){3}(25[0-5]|2[0-4]d|[01]?dd?)$Hex color code
^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$Semantic version (semver)
^(0|[1-9]d*).(0|[1-9]d*).(0|[1-9]d*)(-[a-zA-Z0-9.-]+)?(+[a-zA-Z0-9.-]+)?$
Flags
| Flag | Effect |
|---|---|
| g | Global — find all matches, not just the first |
| i | Case-insensitive matching |
| m | Multiline — ^ and $ match start/end of each line |
| s | Dotall — . matches newlines too |
| u | Unicode support |
Test Your Patterns
Use the Regex Tester on io9.me to test patterns live with real input, see capture groups highlighted, and get instant feedback as you type.