Skip to content

regex

Developer UtilitiesUtilitiesRust

What it is

The regex crate provides regular expressions with guaranteed linear-time matching, avoiding the catastrophic backtracking possible in most other engines.

Compile a Regex once and reuse it. Captures extract groups; the replace family handles substitution. Compilation is expensive, matching is fast.

Installation

cargo add regex

Getting started

The smallest useful thing you can do with it, and what each part means.

Compile once, match many
use regex::Regex;
use std::sync::LazyLock;

// Compiled on first use, then reused for the process lifetime.
static ISBN: LazyLock<Regex> = LazyLock::new(|| {
    Regex::new(r"^(?<prefix>97[89])-(?<rest>[\d-]{10,})$").unwrap()
});

if let Some(caps) = ISBN.captures(input) {
    println!("{} / {}", &caps["prefix"], &caps["rest"]);
}

let cleaned = ISBN.replace_all(text, "[redacted]");
Compiling inside a loop is the classic performance mistake — it can be thousands of times slower than the match itself. LazyLock is the idiomatic fix.

Advanced usage

Where the library earns its place over a simpler alternative.

RegexSet and byte matching
// Test many patterns in a single pass over the input.
let set = RegexSet::new(&[
    r"^GET /api/",
    r"^POST /api/",
    r"\.json$",
])?;

let matched: Vec<_> = set.matches(line).into_iter().collect();

// Work on bytes when the input may not be valid UTF-8.
use regex::bytes::Regex as ByteRegex;
let re = ByteRegex::new(r"(?-u)[\x00-\x08]")?;   // (?-u) disables Unicode mode
RegexSet compiles the alternatives into one automaton, so checking twenty patterns costs roughly one pass rather than twenty.

Errors and fixes

The failures you are most likely to hit, and what actually resolves them.

unrecognized escape sequence / look-around is not supported
The pattern uses a feature this engine deliberately excludes. Rewrite it, or use the fancy-regex crate, which trades away the linear-time guarantee.
Matching is unexpectedly slow
Almost always recompilation in a hot path. Hoist the Regex into a static.

Best practices

  • Compile once with LazyLock or OnceLock, never inside a loop or a request handler.
  • Use named capture groups; positional indices break silently when the pattern changes.
  • Use RegexSet when testing an input against many patterns.
  • Do not look for backreferences or lookaround — they are absent by design; restructure the problem or parse it properly.

Background

Why it exists, and what it was reacting to.

Written by Andrew Gallant, the crate deliberately omits backreferences and lookaround, because supporting them would forfeit the linear-time guarantee that makes it safe on untrusted input.