Regex flavours: POSIX, PCRE, JS, Python, RE2

Regular expressions · Practical · 12 min

Patterns move between grep, editors, databases and languages, and small dialect differences cause silent mismatches.

There is no single regex language; there are families with a shared core.

  • POSIX BRE/ERE: grep, sed, awk, many databases' ~ operators. No \d or lazy quantifiers in the standard; classes like [[:digit:]]. Matching is leftmost-longest. In BRE, ( ) { } + ? | need backslashes.
  • Perl/PCRE family: PCRE2 (PHP, grep -P, nginx, R's perl=TRUE), Perl, Java, .NET, Ruby. The richest feature set: lookarounds, atomic groups, possessive quantifiers, recursion, Unicode properties.
  • JavaScript (ECMAScript): Perl-like, with named groups and lookbehind (ES2018), u/v Unicode modes, no atomic groups or possessive quantifiers, no inline (?x).
  • Python `re`: Perl-like; named groups written (?P<name>...) as well as (?<name>...) (3.12+), atomic groups and possessive quantifiers since 3.11, no \p{...} (the third-party regex module adds it).
  • RE2 family: Go's regexp, Rust's regex, RE2 in C++ and in Google services. Guaranteed linear time, so no backreferences and no lookarounds.

Practical rules: test the pattern in the engine that will run it (sites like regex101 let you pick the flavour), stick to the common core when a pattern must be portable, and check how the host language escapes strings before the regex engine sees them.

Example

# the same idea, "one or more digits", in different tools
grep -E '[0-9]+' file.txt                 # POSIX ERE
grep '[0-9]\{1,\}' file.txt               # POSIX BRE
grep -P '\d+' file.txt                    # PCRE (GNU grep only)
sed -E 's/[0-9]+/N/g' file.txt            # ERE in sed
python3 -c 'import re; print(re.findall(r"\d+", "a1b22"))'   # ['1', '22']
node -e 'console.log("a1b22".match(/\d+/g))'                  # [ '1', '22' ]

# features that differ
#   lookbehind (?<=x)  : PCRE, Python, JS, Java   - not POSIX, Go or Rust
#   backreference \1   : POSIX BRE, PCRE, JS, Python - not Go or Rust
#   atomic (?>...)     : PCRE, Java, .NET, Python 3.11+ - not JS

Remember

  • POSIX tools use [[:digit:]] and leftmost-longest matching
  • PCRE, Java, .NET, Python and JS share the Perl-style syntax with differences at the edges
  • Go and Rust (RE2-style) trade backreferences and lookarounds for linear time

Watch out for

  • Copying a pattern with \d or lookarounds from a JavaScript answer into grep or Go and getting no matches or a compile error.

Check yourself

  1. A pattern uses a backreference \1. Which engine will reject it?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: github.com/google/re2/wiki/Syntax