Regular expression capture groups
Regular expressions

Prev:Matching operations with regular expressions
Next:The theory of regular expressions


Capture operations are available from regexp; no separate vocabulary is needed.
first-match-with-captures ( string regexp -- match/f )

all-matches-with-captures ( string regexp -- matches )

capture ( group match -- slice/f )

capture-bounds ( group match -- from/f to/f )

regexp-match


Ordinary parentheses capture; (?:...) groups without capturing. Groups are numbered from one in opening-parenthesis order, including groups in alternatives that do not participate and groups repeated zero times. Group zero is the whole match. A named group, written (?<name>...), also has a number. Names consist of ASCII letters, digits and underscores, with a letter or underscore first. Names must be unique within the expression.

Each group is a slice of the original input, or f if it did not participate. An empty capture is an empty slice. The groups>> accessor returns the array of groups; capture selects a group by number or name. Slice offsets are zero-based character indices in the original input, with an exclusive end. Use capture-bounds to retrieve both offsets; group zero gives the whole match bounds. Converting a slice with >string discards its original offsets.
USING: prettyprint regexp strings ; "2026-09" R/ (?<year>\d{4})-(\d{2})/ first-match-with-captures "year" swap capture >string .
"2026"


Match selection
The whole match is exactly the one chosen by first-match or all-matching-slices, including leftmost-longest selection and reversed searches. Within that fixed span, captures prefer earlier alternatives and greedy repetitions. For example, matching (a|aa)(a?) against aa captures a in both groups. This is not POSIX longest-subexpression disambiguation. Reluctant quantifier spellings retain Factor's existing greedy behavior.

A repeated group retains its last participating capture. Inner groups that do not participate in a later repetition retain their previous capture. Empty loops are cut off when they revisit the same automaton state at the same input position. Group numbering and capture extraction proceed left to right even for reversed searches.

Lookaround and complement
Positive lookaround can capture outside the whole match. It chooses the longest matching lookahead or lookbehind span, then resolves captures within that span using the same rules. Anchors and boundaries refer to the original input. Groups inside negative lookaround or a complemented expression (?~...) retain their numbers but do not participate, so their values are f.

Execution
The existing DFA chooses each whole match. A separate ordered NFA pass records captures only when requested, and its compiled program is cached on the regular expression. Capture registers belong to each call. Without lookaround, the pass visits each state at most once per input position, avoiding exponential backtracking. Lookaround adds nested matching work. Backreferences remain unsupported.