Forward references — and the name you may have wanted¶
One line: A forward reference is \1 written before group 1 is defined; it is legal in Perl, PCRE2, ABAP, Java, Ruby and JavaScript, a compile error in Python, and absent from Go and Rust's regex. If what you meant was "match something based on what comes later in the text", that is lookahead, and it is a different feature.
Level: 301 · you already use backreferences and want the edges
Keywords on this page: \1 · (…) · (?=…) · (?R) · (?(1)…) — Topics: Portability between engines
First, the four names¶
The words in this area are close enough to swap in memory, so here they are side by side. Only the first two are about reusing captured text; the second two are about position.
| Name | Looks like | Means |
|---|---|---|
| Backreference | (a)\1 |
Match the text group 1 already captured. The reference is written after the group. |
| Forward reference | \1(a) |
The same thing, written before the group. Only ever useful inside a repetition — on the first pass the group holds nothing. |
| Lookahead | a(?=b) |
Assert what follows this position, consuming nothing. This is what "look forward" usually means. |
| Lookbehind | (?<=a)b |
Assert what precedes this position, consuming nothing. |
Two more you will meet in PCRE2 and therefore in ABAP, both often confused with forward references:
- Subroutine call —
(?1)re-runs group 1's pattern (not its text) at this position.(\d\d)-(?1)matches12-34, where(\d\d)-\1matches only12-12. - Conditional —
(?(1)yes|no)branches on whether group 1 participated.
If you came here because a pattern "refers forward", it is worth a moment to decide which of these six you actually want. The rest of this page is about the second one.
What a forward reference does¶
Written on its own, \1(a) is useless: on the first and only pass, group 1 has not matched anything yet. It earns its keep inside a repetition, where a later pass can use what an earlier pass captured.
The pattern below is the smallest honest example. Read it as a loop:
^(?:\1x|(a))+$
^^^^ ^^^
| pass 1 takes this branch: (a) matches "a" and fills group 1
pass 2 takes this branch: \1 is now "a", so \1x matches "ax"
Against aax: pass 1 consumes a, pass 2 consumes ax, the string is done. Against ax there is no second a to fill the group first, so — in most engines — it fails.
Perl¶
Verified output of forward_ref_pl.pl — regenerated by tools/run_examples.py, never hand-typed.
aax match
ax no match
aaxx no match
onetwo: no match
no such group: Reference to nonexistent group in regex; marked by <-- HERE in m/^(?:\2 <-- HERE b|(a))+$/
aax matches; ax and aaxx do not. That is the behaviour the construct is designed for.
The onetwo line is the example this construct is usually introduced with — (\2two|(one))+ — and it is worth knowing that it does not match in Perl. The reason is not the forward reference. Perl keeps a capture across iterations of a quantifier, so on pass 2 group 2 still holds one and the branch wants onetwo where only two is left.
The last line is a different error, and the distinction matters: referring to group 2 in a pattern that only ever has one group is rejected at compile time, exactly as Python rejects a forward reference. "Group not filled yet" and "group does not exist" are not the same complaint.
Catching that error in Perl needs a variable
eval { qr/…/ } around a constant pattern catches nothing, because a constant qr// is compiled when the program is compiled — before eval ever runs. The pattern has to arrive as a string. This bit the first draft of this page.
Python refuses, at compile time¶
Verified output of forward_ref_py.py — regenerated by tools/run_examples.py, never hand-typed.
python compile: invalid group reference 1 at position 5
python compile: invalid group reference 2 at position 2
backwards is fine: True
invalid group reference 1 at position 5 arrives when the pattern is compiled, with no subject in sight. Python's re resolves every group number as it parses, and a number it has not seen yet is an error, full stop. Turn the branches around — group first, reference after — and the identical logic compiles and matches.
This is the single biggest portability cliff in this chapter: a pattern lifted from a Perl or PCRE codebase into Python can fail to compile for a reason that has nothing to do with the text it was meant to match.
JavaScript says yes to everything — for two other reasons¶
Verified output of forward_ref_js.js — regenerated by tools/run_examples.py, never hand-typed.
aax, ax and aaxx all match, and onetwo matches too. JavaScript is not being more capable here; it is applying two rules the other engines do not have:
- A backreference to an unset group matches the empty string. So on pass 1,
\1xis really justx— the branch is optional, not impossible. - Capture groups inside a quantified group are cleared at the start of every iteration. So group 1 is unset again on pass 2, and stays effectively unusable.
Together those mean a forward reference in JavaScript never carries text forward the way it does in Perl. The pattern compiles, it matches more strings than you meant, and nothing reports a problem. The cleared each pass line demonstrates rule 2 on its own.
That is the trap worth taking away from this page: the same pattern, accepted by both engines, means different things. A compile error like Python's is the kinder failure.
Rust¶
Verified output of forward_ref_rs_sh.sh — regenerated by tools/run_examples.py, never hand-typed.
regex: refused
regex parse error:
^(?:\1x|(a))+$
^^
error: backreferences are not supported
fancy-regex: aax true
fancy-regex: ax false
fancy-regex: aaxx false
regex refuses any backreference, forward or not. fancy-regex behaves like Perl — aax yes, ax and aaxx no — which is the answer you want if you are porting Perl patterns to Rust.
ABAP and PCRE2¶
ABAP's PCRE addition (7.55 and later) is the PCRE2 library, so it is Perl's answer:
Real run — PCRE2 10.48 (pcre2grep), macOS 26.6.2 x86-64, 2026-09-21. Subject file holds aax on line 1 and ax on line 2.
Line 1 matches, line 2 does not — Perl's semantics, which is what you should expect from anything in the PCRE family. For ABAP specifically, prefer (?<name>…) with \k<name>: a forward reference by number in ABAP source is a maintenance hazard, since the next developer to add a group renumbers it silently.
The measured summary¶
| Engine | Compiles a forward reference? | Matches aax with the pattern above? |
|---|---|---|
| Perl | yes | yes |
PCRE2 / ABAP PCRE |
yes | yes |
| Ruby | yes | yes |
| Java | yes | yes |
| JavaScript | yes | yes — but also matches ax, for unrelated reasons |
Python re |
no — compile error | — |
Rust fancy-regex |
yes | yes |
Rust regex, Go regexp |
no — no backreferences at all | — |
Every "yes" and "no" in that table is produced by the probe running the pattern, not copied from documentation.
So should you use one?¶
Rarely, and never by number in code someone else will maintain. A forward reference buys you one thing: a repetition whose later passes depend on an earlier pass's capture. That is a real need — validating repeated delimiters, matching balanced pairs — but it is also the shape a reader is least likely to decode correctly, and it is the shape that varies most between engines.
Two safer alternatives, in order of preference:
- Name the group and reference it by name. It survives editing, and it reads.
- Do the repetition in the host language. Match one unit, loop, compare. The Go example in what a backreference is is exactly this move, and it is the one RE2 and Rust's
regexforce on you.
See also¶
- What a backreference is — the ordinary direction, and the unset-group difference in Python and JavaScript.
- Lookahead and lookbehind — if "forward" meant position, this is the page you wanted.
- What a backreference costs — why two of the engines above have no opinion on forward references at all.