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:
cat means “a c, then an a, then a t, adjacent.”+ 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)
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).
Escaping metacharacters
A dozen characters are metacharacters — they have special meaning:
. ^ $ * + ? ( ) [ ] { } | \\ /
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.
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.
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.”
Gotchas
[-a], [a-]). To include ] put it first ([]a]) or escape it. ^ only negates as the first character.Shorthand classes
Common sets have one-letter shortcuts. Capital letters are the negation of the lowercase one.
[0-9] / a non-digit[A-Za-z0-9_] / a non-word charIn the game (JavaScript)
\d, \w and \s are ASCII-only in JavaScript unless you add the u flag with Unicode property escapes. For golf they're much shorter than spelling out a class.Anchors & boundaries
Anchors match a position, not a character — they have zero width.
\w and a non-\wWrap 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 satcategorybobcatconcatenateQuantifiers
A quantifier says how many times the preceding token may repeat.
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.
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.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”.
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.
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.
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:
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.Lookahead & lookbehind
Lookaround asserts that something does (or doesn't) appear next to the current spot without consumingany characters — it's a zero-width condition.
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)
Flags
Flags tweak how the whole pattern behaves. In code they sit after the closing slash (/cat/gi).
^ and $ match at every line break. also matches newlines\u{…} and \p{…})lastIndexUnicode & 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.Common patterns
Reusable building blocks. Treat “validation” regexes as approximations — real email/URL rules are far hairier than a one-liner.
Regex golf tips
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.
Flavor differences
Regex isn't one language — engines differ. The big families are JavaScript, PCRE (PHP, and close to Perl), Python (re / regex) and Java.
regex — not JavaScript(?R)regex only — no JS, no Python re(?<n>) in JS/PCRE/.NET; (?P<n>) in classic PythonIn the game (JavaScript)
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.