One regex, many implementations
Regex started in the 1950s as theoretical computer science, then escaped into the wild via Unix. Every implementation since has added or removed features. Today there are roughly four "families" you'll meet:
PCRE (Perl-Compatible) — the maximalist family. Backreferences, lookaround, recursion, possessive quantifiers, named groups. Used by PHP, PCRE2 itself, and most popular languages' regex engines (Python is close but not identical).
POSIX BRE / ERE — the Unix old guard. grep default is BRE; egrep / grep -E is ERE. No backslashes for grouping in ERE, no lookaround, very portable.
ECMAScript / JavaScript — close to PCRE but with quirks (no possessive quantifiers, g and y flags are stateful via lastIndex, lookbehind is recent).
RE2 / Go — DFA-class. No backreferences, no general lookaround. The trade-off: O(n·m) time, ReDoS-immune.
Where flavor differences bite you
Most of the 80% you'll write is portable. Where flavors diverge:
- Lookbehind — fixed-width in some, variable in others, missing entirely in RE2/Go.
- Named groups —
(?P<name>...)Python style vs(?<name>...).NET/PCRE/JS style. - Backreferences — work in PCRE/Python/JS, missing in RE2.
- Possessive quantifiers —
*+,++,?+work in PCRE, missing in JS. - Unicode — Python defaults to Unicode-aware
\w; JavaScript needs theuflag;grepdepends on locale.
The Languages track (Track 6) maps these explicitly per tool. For now, just know: when a pattern works in one place and fails in another, flavor difference is the first hypothesis.