C.W.K.
Stream
Lesson 05 of 10 · published

Regex Flavors — Same Idea, Different Dialects

~12 min · flavors, pcre, posix, ecmascript

Level 0Pattern-Curious
0 XP0/90 lessons0/15 achievements
0/100 XP to next level100 XP to go0% complete

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 the u flag; grep depends 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.

Code

Same pattern, three flavors·bash
# PCRE / ripgrep / Python — works
rg '(?P<year>\d{4})-(?P<month>\d{2})' file.txt

# POSIX ERE / grep -E — no named groups, falls back to numbered
grep -E '([0-9]{4})-([0-9]{2})' file.txt

# JavaScript — different named-group syntax
// 'foo 2026-05'.match(/(?<year>\d{4})-(?<month>\d{2})/).groups
// { year: '2026', month: '05' }

External links

Exercise

Take any non-trivial pattern you've written and run it through three engines: ripgrep (rg 'PAT' file), Python (re.findall(r'PAT', text)), and JavaScript ('text'.match(/PAT/)). Note any differences in output. If there are none, you've stayed inside the portable 80%.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.