\1 — match the text group 1 matched¶
One line: A backreference re-matches the text a group captured, not its pattern; it exists in every engine here except Go and Rust's regex, which refuse it in exchange for a linear-time guarantee; and the edges — an unset group, a reference written before its group, \10 with one group — are where the six that have it stop agreeing.
Level: reference · one construct, eight engines — chapter 01 has the depth
What it means¶
(a)\1 matches aa. (\w+) \1 matches a doubled word. The reference is to whatever the group captured this time, which is why (\d\d)-\1 matches 12-12 and not 12-34 — matching the pattern again is a subroutine call, a different feature.
| Spelling | Refers to | Accepted by |
|---|---|---|
\1 … \9 |
group by number | all six engines that have backreferences |
\g{1}, \g1 |
group by number, unambiguously | Perl, PCRE2 |
\g{-1} |
the group before this point, relative | Perl, PCRE2 |
\k<1> |
group by number in the named syntax | Ruby, fancy-regex |
\k<name>, (?P=name) |
group by name — the named group page | varies |
Measured¶
Verified output of kw_backreference_sh.sh — regenerated by tools/run_examples.py, never hand-typed.
construct python perl node ruby java go rust fancy
plain aa aa aa aa aa - - aa
unset group no no b no no - - no
forward reference - aax aax aax aax - - aax
\g{1} spelling - aa no no - - - -
\g{-1} relative - aa no no - - - -
\k<1> spelling - - no aa - - - aa
\10 with one group - a\u{8} a\u{8} a\u{8} no a\u{8} - -
case-insensitive backref aA aA - aA aA - - aA
Reading the table¶
- Row 1 is the feature:
(a)\1findsaain six engines. Go and Rust'sregexrefuse — a compile error, which is the honest way to not have a feature. - Row 2, the unset group.
(a)?b\1onb: group 1 never matched. Five engines say a reference to an unset group fails. JavaScript says it matches the empty string and returnsb. This one rule is behind the forward references finding, where JavaScript accepts subjects nobody else does. - Row 3, a reference before its group.
(?:\1x|(a))+compiles in Perl, JavaScript, Ruby, Java andfancy-regex, and Python refuses it at compile time — the chapter's biggest portability cliff. - Rows 4–5,
\g{1}and\g{-1}. Perl alone. JavaScript and Ruby compile them and match nothing, because\gis the letter g there. Python, Java,fancy-regexrefuse. - Row 6,
\k<1>. Ruby andfancy-regexaccept a number in the named-reference syntax; JavaScript compiles it ask<1>and matches nothing. - Row 7,
\10with one group. There is no group 10, so what is\10? Perl, JavaScript, Ruby and Go read it as octal — U+0008, a backspace — and matchedafollowed by one. Java read it as group 1 followed by a literal0and found none. Python refused.fancy-regexrefused. Five answers, one two-character escape. - Row 8,
(?i)(a)\1onaA. Six engines fold the backreference comparison too. Whether they fold non-ASCII the same way is the case-insensitive lesson's last table.
The trap¶
Rows 2 and 3, which are the same trap from two sides: a pattern that means one thing in Perl and is either an error (Python) or a different pattern (JavaScript) elsewhere. The general rule is that a backreference is the feature most likely to be accepted with a changed meaning, because so much of its behaviour is defined at the edges.
And row 1's - cells are not a gap. A backreference makes the match problem NP-hard in general; what a backreference costs is the measurement, and the Go and Rust answer — match two groups, compare in the host language — is linear and readable.
Where it is measured in depth¶
- What a backreference is · Forward references · Backreferences in the replacement · What a backreference costs — the whole chapter.
See also¶
- Capturing group · Named group · Replacement references — the
\1on the other side of a substitution, which is not this. - Recursion and subroutine calls — re-running the pattern instead of re-matching the text.