(*SKIP), (*FAIL), (*COMMIT), (*PRUNE), (*ACCEPT) — steering the backtracker by hand¶
One line: The backtracking control verbs tell a Perl or PCRE2 engine what to do when a match fails past this point — give up entirely, skip ahead, refuse to retry the alternative, or stop matching early and call it a success — and they exist in Perl and PCRE2 (so ABAP) and nowhere else on this page.
Level: reference · the most Perl-specific page in the library
What it means¶
| Verb | On backtracking past it | The job it does |
|---|---|---|
(*FAIL) or (*F) |
fails immediately | an alternative that can never succeed — used with (*SKIP) |
(*SKIP) |
the next attempt starts after the text matched so far, not one character on | "match this, then throw it away and continue from after it" |
(*PRUNE) |
the current starting position is abandoned; the engine advances one character | "no retries from here, try the next offset" |
(*COMMIT) |
the whole match fails; no other starting position is tried | "if this fails, everything fails" |
(*ACCEPT) |
none — the match ends here, successfully, with what has been consumed | early exit with a partial match |
The idiom that pays for the whole table is X(*SKIP)(*F)|Y: match X, discard it, and never let Y match inside something that X matched. It is how you find every comma that is not inside quotes with one pattern.
Measured¶
Verified output of kw_backtracking_verbs_sh.sh — regenerated by tools/run_examples.py, never hand-typed.
construct python perl node ruby java go rust fancy
skip quoted, then comma - "a,b"Xc - - - - - -
same without the verbs X,c X,c X,c X,c X,c X,c X,c X,c
(*COMMIT) forbids retry - no - - - - - -
same without (*COMMIT) ac ac ac ac ac ac ac ac
(*PRUNE) forbids retry - no - - - - - -
same without (*PRUNE) aab aab aab aab aab aab aab aab
(*ACCEPT) ends early - a - - - - - -
Reading the table¶
- Rows 1–2, the
(*SKIP)(*F)idiom. Replacing the first match of"[^"]*"(*SKIP)(*F)|,withXin"a,b",cgives"a,b"Xc— the comma inside the quotes was skipped over, the one outside was replaced. Without the verbs, the same alternation's first match is the quoted string itself, and the result isX,c. Perl alone; every other engine refuses the verbs. - Rows 3–4,
(*COMMIT).a(*COMMIT)b|aconac:amatches,(*COMMIT)is passed,bfails — and the whole match fails, without trying theacalternative that would have worked. Without the verb,ac. - Row 5,
(*PRUNE).a+(*PRUNE)abonaab:a+takes bothas, the verb is passed,abfails; without the verb the engine would give oneaback and matchaab. With it, backtracking intoa+is forbidden, the attempt at offset 0 is abandoned, and no later offset works either. Row 6 is the same pattern without the verb, matching. - Row 7,
(*ACCEPT).a(*ACCEPT)bonacmatchesa— the pattern saysbmust follow, and(*ACCEPT)says stop here anyway.
The trap¶
Portability is not the trap; the verbs refuse to compile anywhere else, which is honest. The trap is reasoning about them. (*PRUNE) and (*COMMIT) are about where the engine goes after a failure, and the mental model needed is the backtracker's, not the pattern's. Where a (*SKIP)(*F) pattern can be replaced by matching the quoted strings and the commas in one alternation and deciding in the host language which was which, the second version is the one the next reader will understand.
Where they earn their keep: pcre2grep, grep -P, and ABAP — places where the pattern is the whole program and there is no host language to decide in.
Where it is measured in depth¶
- Catastrophic backtracking — the search these verbs steer, and the PCRE2 match limit that stops it.
- Atomic groups and possessive quantifiers — the portable subset of the same idea.
See also¶
- Atomic group
(?>…)—(*PRUNE)for one group. - Start-of-pattern options — the other
(*…)syntax, which is unrelated. - Perl's perlre ↗ — the reference, with the verbs' argument forms.