Skip to content

Who supports what

One line: Eleven constructs, handed to five engines, with the answers produced by running them — plus the three engines that answer by refusing the whole category.

Level: reference

Keywords on this page: \1 · (?<name>…) · (?=…) · (?<=…) · (?>…) · *+ · (?R) — Topics: Choosing an engine · Portability between engines

Every table on this page is generated by a program. "yes" means one thing precisely: that engine compiled that pattern. It is not a claim that the construct means the same thing everywhere — forward references is an entire lesson about a pattern that compiles in five engines and means something different in one of them.

The measured table

Verified output of capability_probe_sh.sh — regenerated by tools/run_examples.py, never hand-typed.

does it COMPILE?           python  perl   node   ruby   java  
backreference              yes     yes    yes    yes    yes   
named backref, \k<w>       no      yes    yes    yes    yes   
named backref, (?P=w)      yes     yes    no     no     no    
forward reference          no      yes    yes    yes    yes   
lookahead                  yes     yes    yes    yes    yes   
lookbehind, fixed width    yes     yes    yes    yes    yes   
lookbehind, two widths     no      yes    yes    yes    yes   
lookbehind, variable width no      yes    yes    no     yes   
atomic group               yes     yes    no     yes    yes   
possessive quantifier      yes     yes    no     yes    yes   
recursion                  no      yes    no     no     no    

and does it MATCH 'aax' with the forward reference ^(?:\1x|(a))+$ ?
python  compile error
perl    yes
node    yes
ruby    yes

What to notice

Named backreferences are a spelling war. Perl accepts both; Python accepts only its own (?P=w); JavaScript and Java accept only \k<w>; Ruby accepts \k<w>. Python invented (?P<…>) and PCRE adopted it, which is why the same pattern often works in ABAP and fails in Node.

Forward references split the field cleanly. Everything but Python compiles them. Python rejects them while parsing.

Lookbehind is three separate questions, not one. Python refuses even two fixed-width branches. Ruby accepts branches of different lengths but refuses a bounded repeat. Java and JavaScript accept everything asked here.

Atomic groups and possessive quantifiers are missing only from JavaScript. Python gained both in 3.11. If you have been writing (?>…) off in Python for years, it works now — and what they do to a match is a larger change than the speed they are reached for.

The recursion row says (?R), and that is not the same question as "has recursion". Ruby has recursion and answers no here because Onigmo spells it \g<0>; the two dialects have no overlap, so each engine rejects the other's spelling entirely. PCRE2 has (?R), which means ABAP does; Python's re does not, though the third-party regex module does. Matching nested structures puts every spelling to every engine.

And this is where "yes means it compiled" earns its warning label. Two cells not in this table are silent false positives: JavaScript accepts \g<0> as an identity escape meaning the literal text g<0>, and Rust's regex accepts (?R) because R is its CRLF-mode flag, so the group sets a flag and consumes nothing. Both produce a working pattern that matches something and is not recursion, with no warning from either engine. A probe that only asks "did it compile" cannot tell the difference — which is the argument for the behaviour columns on the lesson pages.

The engines that refuse the category

The probe covers engines that at least have these features. Three more matter and answer differently:

Engine Backreferences Lookaround Guarantee
Go regexp (RE2) none none linear in the subject, always
Rust regex none none linear in the subject, always
Rust fancy-regex yes lookahead, fixed-width lookbehind none — a backtrack limit instead

This is a deliberate trade, not a gap. See what a backreference costs for the measurement.

The full picture, by family

Most engines are one of four lineages, and knowing the lineage predicts the answers better than memorising the table.

Family Members Character
Perl / PCRE Perl, PCRE2, ABAP (PCRE, 7.55+), PHP, R (perl=TRUE) The largest feature set: recursion, \K, atomic groups, conditionals. Backtracking.
Onigmo / Java / .NET Ruby, Java, C#, JavaScript Perl-like, each missing a different corner. JavaScript is the smallest; .NET adds variable lookbehind and named-group stacks.
Python re Python Perl-like, strict about lookbehind width and forward references. The third-party regex module relaxes both.
Automata Go regexp, Rust regex, RE2, grep -E No backreferences, no lookaround, linear time.
POSIX grep, sed, awk, C <regex.h> BRE has \1 by requirement; ERE has it only by common extension. Leftmost-longest matching, which differs from everyone else.

Where ABAP sits

ABAP is in the Perl/PCRE family, which is the single most useful thing to know about it:

  • PCRE addition (7.55 and later) — the PCRE2 library in the kernel. Backreferences \1, named groups, forward references, lookaround with PCRE2's width rules, \K, atomic groups, possessive quantifiers, recursion. Replacement uses $1.
  • REGEX addition (older, obsolete since 7.55) — a POSIX-flavoured engine. Still compiles, still runs, and does not agree with PCRE at the edges. Moving a pattern from REGEX to PCRE deserves a test.
  • CL_ABAP_REGEX with CREATE_PCRE, and CL_ABAP_MATCHER, are the object-oriented way in when you want to compile once and match repeatedly.

A pattern that works in Perl, in pcre2grep, or in a PCRE-mode online tester is the best available prediction of what ABAP will do. A pattern that works in Python is not.

How this page stays honest

The table is regenerated by tools/run_examples.py, which runs capability_probe_sh.sh and pastes its output. Adding an engine means adding a probe_* function; adding a construct means adding one line to the pattern list. Nothing here is transcribed from a documentation page, which is why the named backref rows are split by spelling — the first draft asked Python for \k<w>, got "no", and would have published a table saying Python has no named backreferences at all.

See also