Quick Start
Tutorial
Search & Replace
Tools & Languages
Examples
Reference
Regex Tutorial
Introduction
Table of Contents
Special Characters
Non-Printable Characters
Regex Engine Internals
Character Classes
Character Class Subtraction
Character Class Intersection
Shorthand Character Classes
Dot
Anchors
Word Boundaries
Alternation
Optional Items
Repetition
Grouping & Capturing
Backreferences
Backreferences, part 2
Named Groups
Relative Backreferences
Branch Reset Groups
Free-Spacing & Comments
Unicode Characters & Properties
Mode Modifiers
Atomic Grouping
Possessive Quantifiers
Lookahead & Lookbehind
Lookaround, part 2
Lookbehind Limitations
(Non-)Atomic Lookaround
Keep Text out of The Match
Conditionals
Balancing Groups
Recursion and Subroutines
POSIX Bracket Expressions
Zero-Length Matches
Continuing Matches
Backtracking Control Verbs
Control Verb Arguments
More on This Site
Introduction
Regular Expressions Quick Start
Regular Expressions Tutorial
Replacement Strings Tutorial
Applications and Languages
Regular Expressions Examples
Regular Expressions Reference
Replacement Strings Reference
Book Reviews
Printable PDF
About This Site
RSS Feed & Blog
RegexBuddy—Better than a regular expression tutorial!

Backreferences to Failed Groups

The previous topic on backreferences applies to all regex flavors, except those few that don’t support backreferences at all. Flavors behave differently when you start doing things that don’t fit the “match the text matched by a previous capturing group” job description.

There is a difference between a backreference to a capturing group that matched nothing, and one to a capturing group that did not participate in the match at all. The regex (q?)b\1 with the quantifier inside the group matches b. q? is optional and matches nothing, causing (q?) to successfully match and capture nothing. b matches b and then \1 successfully matches the nothing captured by the group.

In most flavors, the regex (q)?b\1 with the quantifier on the group fails to match b. (q) fails to match at all, so the group never gets to capture anything at all. Because the whole group is optional, the engine does proceed to match b. The engine now arrives at \1 which references a group that did not participate in the match attempt at all. This causes the backreference to fail to match at all, mimicking the result of the group. Since there’s no ? making \1 optional, the overall match attempt fails.

One of the few exceptions is JavaScript. According to the official ECMA standard, a backreference to a non-participating capturing group must successfully match nothing just like a backreference to a participating group that captured nothing does. In other words, in JavaScript, (q?)b\1 and (q)?b\1 both match b. XPath also works this way. The .NET engine handles backreferences like JavaScript only if you set RegexOptions::ECMAScript.

Dinkumware’s implementation of std::regex handles backreferences like JavaScript for all of its grammars that support backreferences. Boost did so too until version 1.46. As of version 1.47, Boost still lets them successfully match nothing when using the default ECMAScript grammar, but fails backreferences to non-participating groups when using the “basic” and “grep” grammars. The libc++ implementation of std::regex fails such backreferences for all grammars.

Backreferences to Non-Existent Capturing Groups

Java treats backreferences to groups that don’t exist as backreferences to groups that exist but never participate in the match. They are not an error, but simply never match anything.

JavaScript treats \1 through \7 as octal escapes when there are fewer capturing groups in the regex than the digit after the backslash. \8 and \9 are an error because 8 and 9 are not valid octal digits. The .NET engine does the same if you specify RegexOptions::ECMAScript which enables support for single-digit octal escapes. All other flavors treat all invalid single-digit backreferences as errors.

Many more flavors support both double-digit backreferences and double-digit octal escapes without a leading zero. These include JavaScript, .NET (with or without RegexOptions::ECMAScript), Perl, Ruby, Tcl, PCRE, PCRE2, PHP, R, and Delphi. Backreferences take precedence over octal escapes. So \12 is a line feed (octal 12 = decimal 10) in a regex with fewer than 12 capturing groups. It would be a backreference to the 12th group in a regex with 12 or more capturing groups.

Java, ICU, XPath, and the JGsoft flavor interpret a double-digit escape as a single-digit backreference followed by a literal digit if the regex has enough groups for the single-digit backreference but not for the double-digit backreference. So (one)\12 matches oneone2.

Things would be less complicated if regex flavors didn’t use the same syntax for backreferences and octal escapes. JavaScript removes support for octal escapes if you create your regex with the /u flag, leaving invalid backreferences as errors. This alone is a good reason to always use /u in new JavaScript code, even if your regex doesn’t actually need the Unicode features that /u enables.

Forward References

Many modern regex flavors, including JGsoft, .NET, Java, ICU, Perl, PCRE, PHP, Delphi, and Ruby allow forward references. They allow you to use a backreference to a group that appears later in the regex. Forward references are obviously only useful if they’re inside a repeated group. Then there can be situations in which the regex engine evaluates the backreference after the group has already matched. Before the group is attempted, the backreference fails like a backreference to a non-participating group does.

If forward references are supported, the regex (\2two|(one))+ matches oneonetwo. At the start of the string, \2 fails because the second group hasn’t even been attempted yet. Trying the other alternative, one is matched by the second capturing group, and subsequently by the first group. The first group is then repeated. This time, \2 matches one as captured by the second group. two then matches two. With two repetitions of the first group, the regex has matched the whole subject string.

JavaScript does not support forward references, but does not treat them as an error. In JavaScript, forward references always find a zero-length match, just as backreferences to non-participating groups do in JavaScript. Because this is not particularly useful, XRegExp makes them an error. In std::regex, Boost, Python, Tcl, and VBScript forward references are an error.

Nested References

A nested reference is a backreference inside the capturing group that it references. Like forward references, nested references are only useful if they’re inside a repeated group, as in (\1two|(one))+. When nested references are supported, this regex also matches oneonetwo. At the start of the string, \1 fails. Trying the other alternative, one is matched by the second capturing group, and subsequently by the first group. The first group is then repeated. This time, \1 matches one as captured by the last iteration of the first group. It doesn’t matter that the regex engine has re-entered the first group. The text matched by the group was stored into the backreference when the group was previously exited. two then matches two. With two repetitions of the first group, the regex has matched the whole subject string. If you retrieve the text from the capturing groups after the match, the first group stores onetwo while the second group captured the first occurrence of one in the string.

The JGsoft, .NET, Java, ICU, Perl, and VBScript flavors all support nested references. PCRE does too, but had bugs with backtracking into capturing groups with nested backreferences. Instead of fixing the bugs, PCRE 8.01 worked around them by forcing capturing groups with nested references to be atomic. So in PCRE, (\1two|(one))+ is the same as (?>(\1two|(one)))+. PCRE2 continues to force groups with nested references to be atomic. This affects languages with regex engines based on PCRE or PCRE2, such as PHP, Delphi, and R.

JavaScript and Ruby do not support nested references, but treat them as backreferences to non-participating groups instead of as errors. In JavaScript that means they always match a zero-length string, while in Ruby they always fail to match. In std::regex, Boost, Python, and Tcl, nested references are an error.

Ad-Free Access and Printable PDF Download

If you find the content on this website helpful they you may want a copy you can read offline or even print, or browse the site as often as you want without ads. You can purchase your own copy of the Regular-Expressions.info printable PDF download. As a bonus, you'll get a lifetime of advertisement-free access to this site!