Regex Syntax Reference: Every Token, Flag and Quantifier
One page per piece of regular expression syntax, written for the moment you are staring at a pattern that nearly works. Each page gives the rule, a worked example with its real output, and the specific mistake that token invites. The tester on every page runs the pattern against your own text, highlights each match, and breaks the pattern down token by token.
Every page here embeds the Regex Tester. Type a pattern and a test string, watch every match highlight as you go, read a plain English breakdown of each token, and check the numbered and named groups it captured.
62 pages in this section.
Category Flags
The g flag: global matching and the lastIndex trap
What the g flag changes in a JavaScript regex, why a reused global pattern skips matches through lastIndex, and when matchAll is the safer choice.
The i flag: case insensitive matching
How the i flag folds case in literals and ranges, what it deliberately leaves alone, and the two non-ASCII characters it starts matching once u is on.
The m flag: multiline anchors
What multiline mode changes about ^ and $, which line terminators JavaScript counts, and why the m flag never makes the dot match a newline.
The s flag: dotAll mode
What dotAll changes, why it has no effect at all on character classes, and the [\s\S] idiom that did the same job before the s flag existed.
The u flag: Unicode mode
What the u flag changes about how a pattern is parsed, the escape forms it unlocks, and the previously tolerated syntax it turns into a hard error.
The y flag: sticky matching at lastIndex
How the sticky flag anchors a match to the current lastIndex, why it is the right tool for a hand written tokenizer, and how it behaves alongside g.
The d flag: capture group start and end offsets
What the d flag adds to a match result, how indices.groups mirrors named captures, and when the extra offsets are worth asking the engine for.
Category Character classes
\d: the digit class, and the digits it refuses
In JavaScript \d is exactly [0-9], even with the u flag. Here is why other engines disagree and what to use when you need Unicode digits.
\D: everything that is not a digit
\D is the exact complement of \d, which makes it a stripping and splitting tool. It also matches newlines, spaces and every letter in every script.
\w: the word character class, underscore included
\w is exactly [A-Za-z0-9_] in JavaScript. That includes the underscore and excludes every accented letter, which is where most \w bugs come from.
\W: non word characters, and the underscore it will not match
\W is the complement of \w, so it never matches an underscore and always matches an accented letter. Both surprises show up when splitting identifiers.
\s: every whitespace character it actually matches
The full list behind \s in JavaScript, including the no break space and the byte order mark, plus the one invisible character it deliberately skips.
\S: non whitespace, and the [\s\S] any character trick
\S is the complement of \s, which makes it a blank check in one character. Paired with \s it also gives the standard match anything class.
The dot: any character except a line terminator
What the dot matches by default, the four characters it skips, how the u and s flags change it, and why it needs no escape inside a character class.
[abc]: character sets and what loses its meaning inside
A bracket set matches one character from a list. Most metacharacters go literal inside it, and only four keep any special meaning at all.
[^abc]: negated character sets that quietly cross newlines
A negated class matches one character that is not in the set, including line terminators. That is why a quoted string pattern runs across lines.
[a-z] ranges: code point order and the A-z bug
Ranges inside a character class run by code point, which is why [A-z] quietly includes six punctuation characters and [a-Z] is a syntax error.
\p{...}: Unicode property escapes, and the flag they need
Property escapes match by Unicode category or script instead of by code point range. Without the u flag they compile into something else entirely.
\b: word boundaries, underscores and accented letters
\b is a zero width assertion defined entirely in terms of \w, which is why user_name has no internal boundary and café has none at its end.
\B: the non word boundary and what it is good for
\B asserts that a position is not a word boundary, which turns it into an inside a word search. It also never matches at the edges of a word.
Category Quantifiers
The * quantifier: zero or more, including nothing at all
The star quantifier succeeds even when it matches nothing, which is why a global match against it returns an empty string at almost every position.
The + quantifier: one or more, and when to prefer it
The plus quantifier requires at least one repetition, which is what makes it the right default for validation where the star quietly accepts nothing.
The ? quantifier: optional, and its two other jobs
A question mark after a token makes it optional. The same character also marks a lazy quantifier and opens a special group, which is why patterns look dense.
{n}: matching exactly n repetitions
An exact count is the clearest quantifier there is, until it is applied to a group, at which point the capture keeps only the final iteration.
{n,}: at least n repetitions, with no upper bound
The open ended count covers everything * and + cannot express, and a stray space after the comma turns the whole quantifier into literal text.
{n,m}: bounded repetition between two counts
A bounded count is inclusive at both ends and greedy toward the maximum. JavaScript has no {,m} shorthand, and writing one produces literal text.
Lazy quantifiers: *?, +?, ?? and {n,m}?
A trailing question mark makes a quantifier prefer the shortest match. It fixes the overreaching tag pattern, and a negated class often fixes it better still.
Atomic groups in JavaScript: emulating them with a lookahead
JavaScript has no (?>...) and no possessive quantifiers. The lookahead and backreference pair gives you the same no backtracking behaviour.
Catastrophic backtracking: why a regex freezes a page
Nested quantifiers over overlapping characters make the work grow exponentially with input length. Here is the shape that causes it and the rewrites for it.
Category Anchors and boundaries
The ^ anchor: start of string, or start of line
Where the caret matches with and without the m flag, why it consumes nothing, and the entirely different job it does inside a character class.
The $ anchor: end of string, and the trailing newline question
Where $ matches in JavaScript, why it refuses to match before a trailing newline when Python and Ruby allow it, and how to write a literal dollar sign.
\A and \z in JavaScript: what to use instead
JavaScript has no \A, \z or \Z. Here is what those anchors silently turn into, and the absolute start and end assertions that survive the m flag.
Anchoring to a line without turning on the m flag
How lookaround assertions give you per line anchors at one position in a pattern while ^ and $ keep their whole string meaning everywhere else.
Category Groups and references
(...) capturing groups: numbering and what comes back
How capture groups are numbered, what a group that did not participate returns, and why quantifying a group throws away everything but the last pass.
(?:...): grouping without creating a capture
A non capturing group applies quantifiers and alternation without taking a number, which is what keeps $1 pointing at the same thing after an edit.
(?<name>...): named capture groups
Named groups survive being reordered, read as documentation and give you $<name> in replacements. They are still numbered underneath.
\1: backreferences that match what a group captured
A backreference matches the exact text a group captured, not the pattern that captured it. Inside a character class the same escape means something else.
\k<name>: backreferences to a named group
\k<name> repeats what a named group captured. Get the name wrong and, without the u flag, the escape quietly becomes a literal letter k.
(?=...): positive lookahead for zero width tests
A lookahead asserts what comes next without consuming it, which is how several independent rules can all be checked from the same position.
(?!...): negative lookahead for exclusion rules
A negative lookahead succeeds when the pattern inside it fails. The classic bug is a greedy quantifier that backtracks until the assertion passes.
(?<=...): positive lookbehind and where it runs
JavaScript allows variable length lookbehind, which Java does not, and matches its contents from right to left. RE2 based engines have none at all.
(?<!...): negative lookbehind to exclude a prefix
A negative lookbehind succeeds when the text before the position does not match. At index zero it always succeeds, which is usually but not always right.
Alternation: precedence and ordered choice
The pipe has the lowest precedence of any regex operator and the branches are tried in order, so ^cat|dog$ and /a|ab/ both surprise people.
Category Escapes and literals
\n: matching a newline, and the double escape trap
\n matches the line feed character. The trap is building a pattern from a string, where the number of backslashes decides what the engine actually sees.
\t: matching tabs in TSV and indented text
\t matches the horizontal tab. Splitting a tab separated row on \s+ instead destroys every empty field, and JavaScript has no \h shorthand.
\r: carriage returns, CRLF and stray line endings
\r matches the carriage return that Windows text puts before every line feed. It is also a line terminator for ^ and $, which not every engine agrees with.
\0: matching the null character safely
\0 matches U+0000, but only while no digit follows it. \01 is an octal escape without the u flag and a syntax error with it, so \x00 is the safer spelling.
\xhh: matching a character by two hex digits
\xhh takes exactly two hex digits and covers U+0000 to U+00FF. Writing four by mistake gives a two digit escape followed by literal text.
\uhhhh: matching a character by code unit
\uhhhh takes exactly four hex digits and matches one UTF-16 code unit, so anything above U+FFFF needs a surrogate pair or the braced form.
\u{...}: code point escapes that need the u flag
The braced escape addresses any code point up to 10FFFF and makes quantifiers apply to whole characters, but only when the u flag is set.
Escaping metacharacters: which ones, and where
Twelve characters need escaping outside a character class and only four inside one. User input needs an escape function before it goes near new RegExp.
Category Common patterns
Regex for email addresses: what can and cannot be validated
No regular expression fully validates an email address. Here is what the built in preset accepts, what it rejects, and the only check that settles it.
Regex for URLs: finding links without overreaching
The built in URL preset needs a scheme and a dotted host, which rules out localhost and bare ports. It also swallows a full stop at the end of a path.
Regex for IPv4 addresses with real octet range checks
The naive four groups of digits pattern accepts 999.999.999.999. Here is the alternation that enforces 0 to 255, and the leading zero case it still allows.
Regex for UUIDs: matching the 8-4-4-4-12 layout
The preset matches the hexadecimal layout of any UUID. Pinning it to version 4 takes two extra character classes, one for the version and one for the variant.
Regex for hex colours: three, six and eight digit forms
The built in preset matches the three and six digit forms and rejects the four and eight digit ones with alpha. Here is the pattern that covers all four.
Regex for ISO dates: matching YYYY-MM-DD without fake days
The preset rejects month 13 and day 32 with two alternations, and still accepts 2026-02-31. No regex can check a calendar, so parse and compare.
Regex for phone numbers, and why strict ones lose customers
Phone formatting varies by country and by habit. The built in US preset does not even match the parenthesised form in its own sample, which is the lesson.
Regex to trim whitespace, collapse runs and drop blank lines
There is no preset for this one. Four short patterns cover trimming, collapsing, per line trimming and removing blank lines, and each has a different failure.
Regex for HTML tags: what the preset matches and what breaks it
The tag preset is fine for finding tags in a known snippet and wrong for parsing a document. A greater than sign inside an attribute value is all it takes.
Regex for numbers: integers, decimals and negative signs
The integer preset splits 3.14 into two matches and the float preset ignores whole numbers. Here is the combined pattern and what it still leaves out.
Regex to extract the text between two delimiters
A lazy quantifier is the usual answer and a negated character class is the better one. Neither can handle nesting, and that limit is worth knowing early.