Core answer: Regular expressions match text by pattern: \d+ matches digits, \w+ word chars, . any char, * zero-or-more, + one-or-more, ? optional, {n,m} counted, [abc] a set, ^ $ anchors, ( ) groups. A phone regex ^1[3-9]\d{9}$ matches Chinese mobiles. Regex is a chainsaw: perfect for log scraping and validation, wrong for parsing HTML/JSON — use real parsers there.
The 20-token survival kit
| Token | Meaning | Example match | |
|---|---|---|---|
| \d \D | digit / non-digit | "5" | |
| \w \W | word char [A-Za-z0-9_] / not | "a_1" | |
| \s \S | whitespace / not | " " | |
| . | any char except newline | "x" | |
| * + ? | 0+ / 1+ / 0-1 times | "aaa" | |
| {2,4} | 2 to 4 times | "aaa" | |
| [abc] [^abc] | set / negated set | "b" | |
| ^ $ | string start / end | anchors | |
| (abc) | capture group | captures | |
| (?:abc) | non-capturing group | groups | |
| a | b | alternation | "a" or "b" |
| \b | word boundary | between \w and \W |
Worked examples
Example 1 — Chinese mobile. ^1[3-9]\d{9}$ — starts with 1, second digit 3–9, then 9 digits. Test: 13812345678 ✓, 12345678901 ✗.
Example 2 — Email (pragmatic). ^[\w.+-]+@[\w-]+\.[\w.]+$ — deliberately loose; RFC-5322-complete regexes run 6,000+ chars and still annoy users. Validate format loosely, confirm by sending email.
Example 3 — Extract dates from logs. (\d{4})-(\d{2})-(\d{2}) captures year/month/day groups: "2025-01-15" → group(1)="2025".
Example 4 — Greedy vs lazy. For "ab", .* greedily eats the whole string; .*? lazily matches each tag separately. The ? after a quantifier flips greediness — the fix for 90% of "regex matched too much".
Example 5 — Catastrophic backtracking. ^(a+)+$ on "aaaaaaaaaaaaaaaaaaaaaaX" explores exponential paths and hangs for years. Avoid nested quantifiers over overlapping classes; possessive/atomic groups or simpler patterns fix it.
Common mistakes and myths
- Parsing HTML with regex — nested, malformed, commented markup defeats regex provably; use a parser (the famous Stack Overflow answer applies).
- Forgetting to escape dots — "a.com" also matches "axcom"; write a\.com for the literal dot.
- Assuming ^$ per line — without the m flag, ^$ match string edges only; "line 2" won't match ^line in multiline text.
- Unicode blindness — \w in many engines skips Chinese; use Unicode-aware flags/classes (\p{L} where supported) for international text.
- Reinventing validation — URLs, emails, IPs have battle-tested libraries; a hand-rolled regex is usually wrong in one edge case that matters.