What Happens When You Type a URL and Press Enter
DNS lookups, TCP and TLS handshakes, HTTP requests, servers, and the browser's rendering pipeline. The whole journey of a web page, explained so it finally clicks.
Read →Regular expressions look like line noise until the building blocks click. Character classes, quantifiers, anchors, groups and lookarounds, with real examples and the pitfalls that cause bugs.
Regular expressions have a reputation: powerful, but unreadable. In practice, you only need a handful of building blocks to handle most everyday tasks, like validating formats, extracting values, searching logs and cleaning up text. Once those blocks click, regex stops being scary.
Examples use JavaScript syntax, but the concepts apply in almost every language.
The simplest regex matches text exactly:
/error/.test('Fatal error occurred') // true
Add flags after the closing slash: i for case-insensitive, g for all matches, m for multiline anchors.
| Pattern | Matches |
|---|---|
. |
Any character except newline |
\d |
A digit (0–9) |
\w |
A word character (letters, digits, underscore) |
\s |
Whitespace (space, tab, newline) |
[abc] |
Any one of a, b or c |
[a-z] |
Any lowercase letter |
[^0-9] |
Anything that's not a digit |
Uppercase versions (\D, \W, \S) mean "not" that class.
| Pattern | Meaning |
|---|---|
* |
Zero or more |
+ |
One or more |
? |
Zero or one (optional) |
{3} |
Exactly 3 |
{2,5} |
Between 2 and 5 |
{2,} |
2 or more |
/\d{3}-\d{4}/.test('555-1234') // true
/colou?r/.test('color') // true, the "u" is optional
^ matches the start of the string (or line with the m flag).$ matches the end.\b matches a word boundary.Anchors are essential for validation. Without them, a pattern can match part of the input:
/\d{5}/.test('abc12345xyz') // true: found 5 digits somewhere
/^\d{5}$/.test('abc12345xyz') // false: the whole string must be 5 digits
Forgetting anchors in validation is one of the most common regex bugs.
Parentheses group parts of a pattern and capture what they match:
const match = '2026-03-14'.match(/^(\d{4})-(\d{2})-(\d{2})$/)
// match[1] = '2026', match[2] = '03', match[3] = '14'
Named groups are more readable:
const { year, month } = '2026-03-14'.match(/(?<year>\d{4})-(?<month>\d{2})/).groups
Use (?:...) for a group you don't need to capture, and | for alternatives: /^(jpg|png|webp)$/.
Quantifiers are greedy by default: they match as much as possible.
'<b>bold</b> and <b>more</b>'.match(/<b>.*<\/b>/)[0]
// '<b>bold</b> and <b>more</b>' (everything between the first and LAST tag)
'<b>bold</b> and <b>more</b>'.match(/<b>.*?<\/b>/)[0]
// '<b>bold</b>' (lazy: as little as possible)
Adding ? after a quantifier makes it lazy.
Check what comes before or after without including it in the match:
(?=...) followed by(?!...) not followed by(?<=...) preceded by(?<!...) not preceded by// Price numbers that come after a dollar sign
'Total: $45, tax: $5'.match(/(?<=\$)\d+/g) // ['45', '5']
// Slug: lowercase letters, digits and single hyphens
/^[a-z0-9]+(?:-[a-z0-9]+)*$/
// Extract all hashtags
text.match(/#\w+/g)
// Collapse repeated whitespace
text.replace(/\s+/g, ' ').trim()
// Find TODO comments in code
/\/\/\s*TODO:?\s*(.+)$/gm
(a+)+$, can take exponential time on certain inputs. With user-supplied input, that's a denial-of-service risk (ReDoS). Keep patterns simple, avoid nested quantifiers, and limit input length. (Security checklist.). * + ? ^ $ ( ) [ ] { } | \ /) when you mean them literally.^ and $.A pattern that describes text, used to search, validate, extract or replace parts of strings. Most programming languages and editors support them.
Greedy quantifiers match as much text as possible; lazy quantifiers (with a trailing ?, like .*?) match as little as possible.
Only for a basic sanity check. Email address rules are complex, so confirm addresses by sending a verification email rather than relying on a strict regex.
DNS lookups, TCP and TLS handshakes, HTTP requests, servers, and the browser's rendering pipeline. The whole journey of a web page, explained so it finally clicks.
Read →There are dozens of HTTP status codes, but about fifteen cover nearly everything. What each one means, when to return it, and the mix-ups (401 vs 403, 301 vs 302) that confuse everyone.
Read →A, AAAA, CNAME, MX, TXT and NS records in plain English, why DNS changes seem slow, and the troubleshooting commands that tell you what is really going on.
Read →