Logics Guru

Regular Expression Reference

Regex syntax in one page: characters, quantifiers, groups, lookaround and flags, plus the traps that make a pattern quietly wrong or catastrophically slow.

3 min read 1 views

Regex syntax is small. Almost all of the difficulty is in a handful of behaviours that are easy to get subtly wrong — greediness, anchors, and what a character class actually contains. This covers the syntax and then those traps.

Character classes#

PatternMatches
.Any character except a newline, unless the dotall flag is set
\d / \DA digit / anything that is not a digit
\w / \WA word character — [A-Za-z0-9_] — / anything else
\s / \SWhitespace, including tabs and newlines / anything else
[abc]Any one of a, b or c
[^abc]Any one character that is not a, b or c
[a-z0-9]A range, or several ranges combined

Inside a class, most metacharacters lose their meaning. [.] is a literal dot. Only ^ (first), ], \ and - (unless first or last) need escaping there.

Quantifiers#

PatternRepeats the preceding item
*Zero or more times
+One or more times
?Zero or once
{3}Exactly three times
{2,}Two or more times
{2,5}Between two and five times
*? +? ?? {2,5}?The same, but lazy — match as few as possible

Quantifiers are greedy by default: they take as much as they can and give characters back only if the rest of the pattern fails. This is the source of more wrong patterns than anything else on the page.

Text
Subject:  <a>first</a> and <a>second</a>

<a>.*</a>    matches the whole string     (greedy)
<a>.*?</a>   matches only <a>first</a>    (lazy)

Anchors and boundaries#

PatternAsserts
^Start of the string, or of a line with the multiline flag
$End of the string, or of a line with the multiline flag
\bA word boundary — between a \w and a non-\w
\BNot a word boundary
\A / \zAbsolute start / end of the string, ignoring multiline

Groups#

PatternMeaning
(abc)Capturing group — available afterwards as $1, \1
(?:abc)Non-capturing: groups for structure without capturing
(?<name>abc)Named capture, read back by name
a|bAlternation — a or b
\1Backreference: matches what group 1 already matched

Lookaround#

Lookaround asserts what is next to the match without consuming it, so it does not appear in the result.

PatternMeaning
(?=abc)Lookahead — what follows is abc
(?!abc)Negative lookahead — what follows is not abc
(?<=abc)Lookbehind — what precedes is abc
(?<!abc)Negative lookbehind — what precedes is not abc
Text
\d+(?= dollars)     matches 100 in "100 dollars", not in "100 euros"
(?<=\$)\d+          matches 100 in "$100", and the $ stays out of the match

Flags#

FlagEffect
iCase insensitive
gGlobal — find every match, not just the first
mMultiline — ^ and $ match at line breaks
sDotall — . also matches a newline
uUnicode mode
xExtended — ignore whitespace and allow comments in the pattern

Catastrophic backtracking#

Nested quantifiers over overlapping alternatives can make matching take exponential time. A pattern that runs instantly on ten characters can hang a server on thirty. This is a genuine denial-of-service class, usually written ReDoS.

Text
(a+)+$        against "aaaaaaaaaaaaaaaaaaaaaaaaaaX"
              — the engine tries every way to split the a's before failing

Avoid it by not nesting quantifiers over the same characters, by making inner groups possessive or atomic where the engine supports it ((?>a+)), and by never building a pattern out of untrusted input.

The traps worth remembering#

  • \d is not "0-9" in Unicode mode — with the u flag in some engines it matches digits from other scripts too. Use [0-9] when you mean ASCII.
  • . stops at newlines unless you set dotall. Multi-line input is where patterns silently match nothing.
  • $ can match before a trailing newline. Use \z when you truly mean the end.
  • A dot in a class is literal[.] needs no escape, and [\.] is the same thing written less clearly.
  • Do not parse HTML with regex. Nesting is not a regular language. Use a parser.
  • Do not validate email addresses with regex. The grammar is far larger than anyone expects. Check for an @ with something either side, then send a confirmation email — which is the only real proof anyway.
Mustasim Ali

Mustasim Ali

Senior Software Engineer & Technical Lead

Full-stack engineer working in PHP and Laravel since 2019. I lead a development team building web and mobile products, and spend most of my time in Laravel, Node.js, Vue and React against MySQL and MongoDB. Logics Guru is where I write up the things I had to work out the hard way — the architecture decisions, the debugging sessions, and the small utilities I kept rebuilding until I put them somewhere permanent. Everything here is what I actually use.