A backreference asks a regular expression to match the exact text already captured by a group. That small trick turns a pattern from “find something shaped like this” into “find the same thing again”—useful when domino ends must connect, words must not repeat, or a later run of characters must equal an earlier run. section 3.5 section 5.5
The notation refers to a numbered capturing group: \2 reuses group 2, while \3 and \4 can reuse two earlier captures in sequence. Numbering counts every capturing pair of parentheses, including an outer group that may exist only to repeat a larger pattern. Non-capturing groups, written (?:…), group patterns without creating a captured value. section 5.5 section 5.6
Backreferences become more useful when combined with assertions and repetition:
- A lookahead can require the next tile to begin with the digit captured at the end of the current tile, without consuming that next tile yet. section 3.5
- A negative lookahead can reject a word when the same captured word occurs later; word boundaries prevent a mere prefix from counting as a duplicate. section 5.5
- A quantifier can express “twice the captured run,” as in \3\3 or \3{2}, rather than merely matching a fixed pair of characters. section 5.11
- Two captured runs can be concatenated in a lookahead, making an encoded Fibonacci-like next value match the preceding two values joined together. section 5.14
A clever pattern still needs adversarial tests
The pattern ^@(?: \@{2})*$ correctly recognizes a first @ followed by repeated pairs of @, but it does not recognize the intended growing runs such as @ @@ @@@@ or @@@ @@@@@@. The missing idea is not more @ characters: it is a backreference to the previously captured run, repeated twice. A plausible explanation of regex pieces can therefore coexist with the wrong overall constraint. section 5.11 section 5.12
Complexity has a cost. A verbose pattern can make group roles and lookaheads readable, but a single pass may still miss overlapping relationships. For a Fibonacci-like sequence, checking both the full sequence and its tail catches an invalid middle transition that a pattern examining values two at a time would otherwise accept. Pause before trusting a match: what relation did the captures actually verify, and what relation slipped between them? section 5.14
# Mismatched ends in bad, malformed syntax in awful
>>> good = '{1:3}{3:3}{3:6}{6:1}{1:3}{3:3}{3:3}'
>>> bad = '{1:3}{3:3}{6:1}{1:3}{3:3}{3:6}{3:3}'
>>> awful = '{1:3}{{3:5}}{5:2}'
>>> pat = r'^(({[1-6]:([1-6])})(?=$|{\3))+$'
>>> for play in (good, bad, awful):
... match = re.search(pat, play)
... if match:
... print(match.group(), "wins!")
... else:
... print(play, "loses!")
{1:3}{3:3}{3:6}{6:1}{1:3}{3:3}{3:3} wins!
{1:3}{3:3}{6:1}{1:3}{3:3}{3:6}{3:3} loses!
{1:3}{{3:5}}{5:2} loses!
Inspect a compact winning-domino pattern: group 3 captures one tile end, and the lookahead requires that captured digit at the next tile’s start. section 3.5

