Characters & escapes
Details →| Syntax | Meaning · example |
|---|---|
| abc | the characters a, b, c in order |
| . | any character except a line break |
| \. \* \\ | a metacharacter matched literally |
| \t \n \r | tab, newline, carriage return |
Classes & shorthands
Details →| Syntax | Meaning · example |
|---|---|
| [abc] | one of a, b or c |
| [^abc] | any character except a, b or c |
| [a-z] | a range: any lowercase letter |
| \d \D | a digit / not a digit |
| \w \W | a word character [A-Za-z0-9_] / not one |
| \s \S | whitespace / not whitespace |
| \p{L} | any letter in any script (with the u flag) |
Anchors
Details →| Syntax | Meaning · example |
|---|---|
| ^ | start of the text (of a line with m) |
| $ | end of the text (of a line with m) |
| \b | a word boundary |
| \B | not a word boundary |
Quantifiers
Details →| Syntax | Meaning · example |
|---|---|
| * | zero or more |
| + | one or more |
| ? | optional: zero or one |
| {3} | exactly 3 |
| {2,5} | between 2 and 5 |
| {2,} | 2 or more |
| *? +? ?? | lazy: as few as possible |
Groups & backreferences
Details →| Syntax | Meaning · example |
|---|---|
| (abc) | a capturing group |
| (?:abc) | a group that doesn't capture |
| (?<name>abc) | a named capturing group |
| \1 | the text group 1 captured |
| \k<name> | the text a named group captured |
| a|b | a or b |
Lookaround
Details →| Syntax | Meaning · example |
|---|---|
| (?=abc) | followed by abc (lookahead) |
| (?!abc) | not followed by abc |
| (?<=abc) | preceded by abc (lookbehind) |
| (?<!abc) | not preceded by abc |
Flags
Details →| Syntax | Meaning · example |
|---|---|
| i | ignore case |
| g | global: every match, not just the first |
| m | multiline: ^ and $ at every line |
| s | dotall: . also matches line breaks |
| u | unicode: \p{…} and \u{…} |
| y | sticky: match only at lastIndex |
Rules & examples
01 How regex works
A regular expression (regex) is a tiny pattern language for describing text. The engine walks your pattern and the input together, left to right, trying to make every part of the pattern line up with characters in the string. If it can, the string matches.
Two questions cover almost everything you do:
match each char
A pattern like cat means “a c, then an a, then a t, adjacent.”
how many
Quantifiers like + and * say how many times the previous thing may repeat.
By default a regex matches if the pattern is found anywhere in the string — it doesn't have to cover the whole thing unless you anchor it.
In the game (JavaScript)
02 Literal characters
Most characters match themselves. Letters, digits and spaces are all literals: regex matches the text “regex”, 42 matches “42”. Matching is case-sensitive by default, so Cat does not match “cat” (the i flag changes that).
PracticeAcademy: Hunter basics
03 Escaping metacharacters
Metacharacters are the dozen characters with a special meaning in regex:
. ^ $ * + ? ( ) [ ] { } | \\ /
To match one literally, put a backslash in front of it. \. matches a real dot, \+ a real plus, \\ a real backslash. Inside a character class most of these lose their power and need no escape.
PracticeAcademy: Hunter basics · Play: Escaping hunts
04 The dot ( . )
The dot . matches any single character except a line break (unless the s / dotall flag is set). It is the most over-used token in regex — when you really mean “any letter” or “any digit”, a class is safer.
Here c.t needs exactly one character between the c and t — so “ct” (zero) and “caat” (two) both fail.
PracticeAcademy: Hunter basics
05 Character classes [ ]
Square brackets define a set — match exactly one character from inside it. [aeiou] matches any one vowel. Use a hyphen for a range: [a-z], [0-9], [A-Fa-f0-9] (a hex digit). Lead with ^ to negate: [^0-9] is “any character that is not a digit.”
| Token | Meaning |
|---|---|
| [abc] | one of a, b or c |
| [a-z] | any lowercase letter |
| [0-9a-fA-F] | a hexadecimal digit |
| [^aeiou] | anything except a lowercase vowel |
| [.\-] | a literal dot or hyphen (most metachars are literal inside a class) |
Gotchas
[-a], [a-]). To include ], escape it ([\]a]): in JavaScript [] is an empty class, so []a] doesn't work. ^ only negates as the first character.PracticeAcademy: Character classes · Pack: Character castles · Play: Character class hunts
06 Shorthand classes
Shorthand classes are one-letter shortcuts for common sets, like \d for any digit. Each capital letter is the negation of its lowercase one.
| Token | Meaning |
|---|---|
| \d \D | a digit [0-9] / a non-digit |
| \w \W | a word char [A-Za-z0-9_] / a non-word char |
| \s \S | whitespace (space, tab, newline…) / non-whitespace |
| \t \n \r | tab, newline, carriage return |
In the game (JavaScript)
\d and \w are ASCII-only, even with the u flag; use \p{L} or \p{N} for other scripts. \s already matches Unicode spaces. For golf they're much shorter than spelling out a class.PracticeAcademy: Character classes
07 Anchors & boundaries
Anchors match a position, not a character — they have zero width.
| Token | Meaning |
|---|---|
| ^ | start of the string (or line, with the m flag) |
| $ | end of the string (or line, with the m flag) |
| \b | a word boundary — the edge between a \w and a non-\w |
| \B | a position that is not a word boundary |
Wrap a pattern in ^…$ to force it to match the entire string. \bcat\b matches the whole word “cat” but not “category” or “scatter”.
cata cat satcategorybobcatconcatenatePracticeAcademy: Anchors & boundaries · Pack: Anchor's away · Play: Anchor hunts
08 Quantifiers
A quantifier says how many times the preceding token may repeat.
| Token | Meaning |
|---|---|
| * | zero or more |
| + | one or more |
| ? | zero or one (optional) |
| {3} | exactly 3 |
| {2,5} | between 2 and 5 |
| {2,} | 2 or more |
They attach to the thing right before them — a character, a class, or a group. colou?r makes the u optional (matches “color” and “colour”); (ab)+ repeats the pair.
PracticeAcademy: Quantifiers · Pack: Quantifier quarry · Play: Quantifier hunts
09 Greedy, lazy & possessive
By default quantifiers are greedy: they grab as much as possible, then give characters back if the rest of the pattern needs them. Add ? to make one lazy — it takes as little as possible.
Classic example: against <a><b>, the greedy <.*> matches the whole thing, while the lazy <.*?> stops at the first >.
Possessive & atomic (not in JavaScript)
a*+) and atomic groups ((?>…)) that never give characters back — a guard against catastrophic backtracking. JavaScript has neither; emulate atomic with a lookahead + backreference.PracticeAcademy: Quantifiers
10 Alternation & grouping
| means “or” and has the lowest precedence — it splits the whole pattern unless you contain it with parentheses. cat|dog matches either word; gr(a|e)y matches “gray” or “grey”, whereas gra|ey would mean “gra” or “ey”.
PracticeAcademy: Groups & backreferences · Play: Alternation hunts
11 Groups: capture & name
Parentheses do two jobs: they group tokens so a quantifier or | applies to all of them, and they capture what matched for later reuse.
| Token | Meaning |
|---|---|
| (…) | capturing group — numbered 1, 2, 3… left to right |
| (?:…) | non-capturing group — groups without the bookkeeping |
| (?<name>…) | named capturing group |
Use (?:…) when you only need grouping (it's faster and keeps your group numbers tidy), and names when a pattern has several captures worth labelling.
PracticeAcademy: Groups & backreferences · Pack: Tricky patterns · Play: Group hunts
12 Backreferences
A backreference matches the same text a group already captured. \1 refers to group 1, \2 to group 2, \k<name> to a named group. This is how you require repetition:
| Token | Meaning |
|---|---|
| (.)\1 | any character followed by itself — a double letter |
| (.)(.)\2\1 | a 4-char palindrome (e.g. “abba”) |
| (.).*\1 | same character appears again later |
Backref vs. class
(.)\1 requires the same character twice — that's different from [a-z][a-z] (any two letters). Backreferences are what let regex check “the same thing again,” which a plain class can't express.PracticeAcademy: Groups & backreferences
13 Lookahead & lookbehind
Lookaround asserts that something does (or doesn't) appear next to the current spot without consuming any characters — it's a zero-width condition.
| Token | Meaning |
|---|---|
| (?=…) | positive lookahead — followed by … |
| (?!…) | negative lookahead — not followed by … |
| (?<=…) | positive lookbehind — preceded by … |
| (?<!…) | negative lookbehind — not preceded by … |
A password-style rule “contains a digit and a letter” stacks lookaheads at the start: ^(?=.*\d)(?=.*[a-z]).+$. Each (?=…) checks the whole string from position 0, then the match continues. Lookbehind requires a fixed (or bounded) width in most engines.
In the game (JavaScript)
PracticeAcademy: Lookarounds · Play: Lookaround hunts
14 Flags
Flags are single letters that change how the whole pattern matches, like i for case-insensitive. In code they sit after the closing slash (/cat/gi).
| Token | Meaning |
|---|---|
| i | ignore case |
| g | global — find all matches, not just the first |
| m | multiline — ^ and $ match at every line break |
| s | dotall — . also matches newlines |
| u | unicode mode (enables \u{…} and \p{…}) |
| y | sticky — match only at lastIndex |
| x | extended/verbose: ignore whitespace & allow comments (PCRE/Python; not JS) |
15 Unicode & properties
With the u flag you can match by Unicode property: \p{L} is any letter in any script, \p{N} any number, \p{Emoji} emoji, and \P{…} negates. \u{1F600} matches a code point by hex value.
Without u, a regex works on UTF-16 code units, so an emoji or other astral character counts as two “characters” — usually not what you want. Property escapes are the clean way to handle real-world text.
Engine support
u), PCRE, Python (via the regex module), Java and others, but the exact property names differ. Stick to the common ones (L, N, P, script names) for portability.16 Common patterns
These are short, reusable patterns for everyday formats: integers, decimals, emails, hex colours and ISO dates. Treat “validation” regexes as approximations — real email/URL rules are far hairier than a one-liner.
| Token | Meaning |
|---|---|
| ^\d+$ | a whole non-negative integer |
| -?\d+(\.\d+)? | an optional-sign decimal number |
| ^[\w.+-]+@[\w-]+\.[\w.-]+$ | a rough email shape |
| ^#?[0-9a-fA-F]{6}$ | a 6-digit hex colour |
| ^\d{4}-\d{2}-\d{2}$ | an ISO date (YYYY-MM-DD) |
PracticeAcademy: Real-world validators · Play: Mixed hunts
17 Tips for shorter patterns
Golf is the art of the shortest pattern that catches every target and spares every decoy. The board only asks “does it match anywhere” — so you rarely need anchors or to describe the whole word.
- Find the smallest distinguishing feature. If every target contains
qand no decoy does, the answer is justq. - Prefer a class over alternation:
[cb]atbeatscat|bat. - Shorthands are short:
\dover[0-9],\wover[A-Za-z0-9_]. - Drop anchors unless a decoy forces them. Add
^or$only to exclude a near-miss. - Make differences optional with
?instead of branching. - Reach for a backreference when targets share a repeat the decoys lack.
Try shrinking this — both cat and bat are targets, “rat” is a decoy:
Ready to compete? The daily hunt, practice packs and the playground are where to put this into practice.
PracticeAcademy: Golf techniques
18 Flavor differences
Regex flavors are the dialects of different regex engines, and they don't all support the same features. The big families are JavaScript, PCRE (PHP, and close to Perl), Python (re / regex) and Java.
| Token | Meaning |
|---|---|
| Lookbehind | JS (ES2018+), PCRE, Python, Java — fixed-width in most; PCRE/Python allow more |
| Possessive / atomic | PCRE, Java, Python regex — not JavaScript |
Recursion (?R) | PCRE & Python regex only — no JS, no Python re |
| Named group | (?<n>) in JS/PCRE/.NET; (?P<n>) in classic Python |
| x / verbose flag | PCRE, Python, Java — not JavaScript |
In the game (JavaScript)
19 Performance & backtracking
Most regexes are fast, but nested quantifiers over the same characters can explode. (a+)+$ against a long run of “a” followed by “!” forces the engine to try an exponential number of splits — catastrophic backtracking.
- Avoid a quantifier inside a quantifier that can match the same thing (
(a+)+,(.*)*). - Make inner pieces mutually exclusive so there's only one way to match.
- Anchor with
^/$and prefer specific classes over.to cut the search space. - In engines that have them, possessive quantifiers / atomic groups stop the backtracking entirely.