BurntSushi/ripgrepUnlicense3fce3b5Report / request removal

The PCRE2 Matcher

PCRE2 is ripgrep’s optional regex backend for patterns that need features beyond the default Rust regex engine, especially look-around and backreferences. It is exposed through the grep_pcre2 crate only when the pcre2 feature is enabled.

The backend adapts PCRE2 matching to ripgrep’s common matcher interface, including ordinary matches, iteration, capture locations, and named-capture lookup. Runtime engine selection can be explicit or automatic, but the supplied excerpts do not show the Cargo or linker implementation for the PCRE2 C library.

Sources: crates/core/flags/defs.rs:5730-5743, crates/pcre2/src/matcher.rs:302-305, crates/pcre2/src/matcher.rs:319-329, crates/pcre2/src/matcher.rs:339-341

Core concepts

PCRE2 backend

The PCRE2 backend is the opt-in engine selected with --pcre2 or --engine=pcre2, primarily to support look-around and backreferences.

Sources: crates/core/flags/defs.rs:5730-5739

Default engine

The default engine is Rust’s regex implementation, technically backed by regex-automata; it is the first engine attempted by automatic selection.

Sources: crates/core/flags/lowargs.rs:541-551

Automatic engine choice

Automatic selection means ripgrep first tries the default engine and switches to PCRE2 when the pattern does not compile there, if PCRE2 is available.

Sources: crates/core/flags/lowargs.rs:549-554

Matcher adapter

The matcher adapter is RegexMatcher, which stores a compiled Regex and a map from capture names to capture indexes.

Sources: crates/pcre2/src/matcher.rs:302-305

Optional availability

PCRE2 availability is a build-time property represented by the pcre2 feature; without that feature, requesting PCRE2 returns an error.

Sources: crates/core/flags/hiargs.rs:415-423

How ripgrep chooses an engine

The engine modes form a small policy surface: the default mode stays with Rust’s engine, Auto retries with PCRE2 after a default-engine compilation failure, and PCRE2 requests the optional backend directly.

ModeUser-facing choiceBehavior
Default--engine=defaultUses Rust’s default regex engine.
Auto--engine=auto or --auto-hybrid-regexTries the default engine, then PCRE2 if available and needed.
PCRE2--engine=pcre2 or --pcre2Uses PCRE2 if the build includes it.

The automatic choice is made from whether the pattern compiles, not from observed behavior while searching files.

The choice applies to every regex supplied to ripgrep, including patterns provided through multiple --regexp or --file options.

The workflow shows the two engine attempts described by EngineChoice; the selected result is represented by PatternMatcher in the flag-resolution path.

Sources: crates/core/flags/lowargs.rs:541-555, crates/core/flags/defs.rs:341-345

What the PCRE2 matcher adds

PCRE2 enables look-around and backreferences that the default engine does not support in the relevant selection flow.

The backend also exposes configuration for case handling, line behavior, word and whole-line matching, Unicode modes, and JIT operation. These options configure the builder rather than changing the engine-selection policy.

Builder optionPlain-language effect
caselessEnables case-insensitive matching.
case_smartEnables smart case selection based on uppercase literals.
multi_lineConfigures multiline matching.
crlfConfigures CRLF line-terminator handling.
wordRequests word-boundary matching.
whole_lineRequests whole-line matching.
ucpConfigures Unicode character-property behavior.
utfConfigures UTF matching.
jitEnables JIT configuration.
jit_if_availableEnables JIT when available.

build_many combines multiple patterns with alternation, optionally escapes them as fixed strings, applies whole-line or word wrappers, and then compiles the resulting expression.

let mut singlepat = if patterns.is_empty() {
    r"[^\S\s]".to_string()
} else {
    pats.join("|")
};
if self.case_smart && !has_uppercase_literal(&singlepat) {
    builder.caseless(true);
}
if self.whole_line {
    singlepat = format!(r"(?m:^)(?:{})(?m:$)", singlepat);
} else if self.word {
    singlepat = format!(r"(?<!\w)(?:{})(?!\w)", singlepat);
}

This is the important normalization step: user-facing matching modes become part of the compiled PCRE2 pattern before compilation.

case_smart enables caseless matching only when has_uppercase_literal finds no uppercase literal, while escaped characters are skipped during that scan.

The tests demonstrate that word(true) matches -2 in abc -2 foo, while an explicit \b-2\b pattern does not; they also show that crlf(true) changes $ handling at a CRLF boundary.

Sources: crates/pcre2/src/matcher.rs:94-97, crates/pcre2/src/matcher.rs:148-151, crates/pcre2/src/matcher.rs:160-163, crates/pcre2/src/matcher.rs:191-194, crates/pcre2/src/matcher.rs:205-208, crates/pcre2/src/matcher.rs:225-228, crates/pcre2/src/matcher.rs:258-261, crates/pcre2/src/matcher.rs:273-276, crates/pcre2/src/matcher.rs:45-85, crates/pcre2/src/matcher.rs:49-76, crates/pcre2/src/matcher.rs:422-432, crates/pcre2/src/matcher.rs:443-451, crates/pcre2/src/matcher.rs:455-477

How matching reaches the common interface

RegexMatcherBuilder::new starts with a PCRE2 RegexBuilder and default values for the adapter’s extra flags. A single pattern then flows through build into build_many.

Building a PCRE2 matcher — How does a pattern become a RegexMatcher?

Evidence

The resulting RegexMatcher implements the matcher operations used by ripgrep: find_at calls the compiled regex, try_find_iter streams matches to a callback, and captures_at fills reusable capture locations.

Named captures are resolved through the names map, while RegexCaptures exposes capture count and indexed locations through len and get.

Compilation failures are represented as ErrorKind::Regex, and the underlying error text is preserved for formatting.

Sources: crates/pcre2/src/matcher.rs:22-30, crates/pcre2/src/matcher.rs:37-39, crates/pcre2/src/matcher.rs:319-329, crates/pcre2/src/matcher.rs:343-360, crates/pcre2/src/matcher.rs:362-373, crates/pcre2/src/matcher.rs:302-305, crates/pcre2/src/matcher.rs:339-341, crates/pcre2/src/matcher.rs:391-394, crates/pcre2/src/matcher.rs:397-399, crates/pcre2/src/matcher.rs:401-403, crates/pcre2/src/error.rs:25-32, crates/pcre2/src/error.rs:43-47

How it connects

The high-level grep facade re-exports grep_pcre2 as pcre2 only when the pcre2 feature is enabled, alongside the matcher, regex, searcher, printer, and CLI crates.

For workspace placement and the facade’s role, see Repository and Crate Map. For the CLI’s resolved engine flags, see CLI Entry and Flag Parsing. For the shared matcher contract implemented by RegexMatcher, see The Matcher Trait and Internal Iteration.

The supplied excerpts establish optional feature gating and matcher behavior, but not how the PCRE2 C library is linked or when a build falls back to compiling it from source. Those build and static-linking mechanics belong with Building and Installing.

Sources: crates/grep/src/lib.rs:15-21, crates/core/flags/hiargs.rs:415-423

Key takeaways

  • PCRE2 is optional and adds look-around and backreference support.
  • Auto tries the default engine first and switches to PCRE2 when compilation fails, if PCRE2 is available.
  • RegexMatcherBuilder normalizes patterns and matching modes before compiling RegexMatcher.
  • The adapter exposes ordinary matches, iteration, captures, and named-capture lookup.
  • Linking and source-build details are not shown in this source pack; consult Building and Installing.

Sources: crates/core/flags/defs.rs:5730-5743, crates/core/flags/lowargs.rs:549-554, crates/pcre2/src/matcher.rs:12-18, crates/pcre2/src/matcher.rs:45-85, crates/pcre2/src/matcher.rs:302-305, crates/pcre2/src/matcher.rs:319-329, crates/pcre2/src/matcher.rs:339-341, crates/pcre2/src/matcher.rs:343-360, crates/pcre2/src/matcher.rs:362-373

Want this for your repos?

Try Angada AI Wiki