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\dor 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'sperl=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/vUnicode 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-partyregexmodule adds it). - RE2 family: Go's
regexp, Rust'sregex, 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 JSRemember
- 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.