TL;DR: The
regexcrate provides Rust's standard regular expression support. It is fast (linear time guarantee, no catastrophic backtracking), safe (no unsafe code in the regex engine), and Unicode-aware by default. Compile patterns withRegex::new(), check matches with.is_match(), extract captures with.captures(), and replace text with.replace(). Compile regexes once withLazyLockoronce_cell; recompiling on every call is expensive.
How Do You Use the regex Crate?
# Cargo.toml
[dependencies]
regex = "1"use regex::Regex;
fn main() {
let re = Regex::new(r"\d{4}-\d{2}-\d{2}").unwrap(); // yyyy-mm-dd
// Check if pattern exists
println!("{}", re.is_match("Today is 2026-04-15")); // true
println!("{}", re.is_match("No date here")); // false
// Find the match
if let Some(mat) = re.find("Event on 2026-04-15 at noon") {
println!("found: {} ({}..{})", mat.as_str(), mat.start(), mat.end());
// found: 2026-04-15 (9..19)
}
}How Do You Extract Capture Groups?
Wrap parts of the pattern in (...) to create capture groups; access them by index or name.
use regex::Regex;
fn main() {
// Named captures: (?P<name>pattern)
let re = Regex::new(
r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})"
).unwrap();
let text = "Launch date: 2026-04-15";
if let Some(caps) = re.captures(text) {
println!("year: {}", &caps["year"]); // 2026
println!("month: {}", &caps["month"]); // 04
println!("day: {}", &caps["day"]); // 15
// By index
println!("full match: {}", caps.get(0).unwrap().as_str()); // 2026-04-15
}
}How Do You Find All Matches?
.find_iter() returns an iterator over all non-overlapping matches.
use regex::Regex;
fn main() {
let re = Regex::new(r"\b\w+@\w+\.\w+\b").unwrap(); // simple email pattern
let text = "Contact [email protected] or [email protected] for info";
for mat in re.find_iter(text) {
println!("email: {}", mat.as_str());
}
// email: [email protected]
// email: [email protected]
// Collect all matches
let emails: Vec<&str> = re.find_iter(text).map(|m| m.as_str()).collect();
}How Do You Replace Text?
.replace() replaces the first match; .replace_all() replaces all matches. Use $1, $name in the replacement string.
use regex::Regex;
fn main() {
let re = Regex::new(r"(\d{4})-(\d{2})-(\d{2})").unwrap();
let text = "Date: 2026-04-15, Updated: 2026-03-01";
// Replace first match; reorder to US format (mm/dd/yyyy)
let result = re.replace(text, "$2/$3/$1");
println!("{result}"); // Date: 04/15/2026, Updated: 2026-03-01
// Replace all matches
let result = re.replace_all(text, "$2/$3/$1");
println!("{result}"); // Date: 04/15/2026, Updated: 03/01/2026
// Dynamic replacement with closure
let result = re.replace_all(text, |caps: ®ex::Captures| {
format!("{}/{}/{}", &caps[2], &caps[3], &caps[1])
});
}How Do You Avoid Recompiling Regexes on Every Call?
Compile once with LazyLock (Rust 1.80+) or once_cell::sync::Lazy; recompiling on each call is the most common performance mistake.
use std::sync::LazyLock;
use regex::Regex;
// Compiled once at first use; zero-cost thereafter
static EMAIL_RE: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}").unwrap()
});
static DATE_RE: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(r"\d{4}-\d{2}-\d{2}").unwrap()
});
fn validate_email(input: &str) -> bool {
EMAIL_RE.is_match(input) // no compilation overhead
}Frequently Asked Questions
Yes; the regex crate uses a finite automaton engine that guarantees O(n) time complexity (linear in input length). It does not support backreferences or lookahead/lookbehind, which are the features that cause exponential backtracking in other regex engines. For those features, use the fancy-regex crate (but with no backtracking guarantees).
Use the (?i) flag at the start of the pattern:
let re = Regex::new(r"(?i)hello").unwrap();
re.is_match("HELLO"); // trueThe regex! macro (from the regex crate) compiles the regex at compile time; no unwrap() needed, no runtime cost. Available in nightly or via the once_cell pattern. For most projects, LazyLock is simpler.
The regex crate requires std. For no_std use, try regex-automata (the underlying engine, available no_std) or regex-lite (a smaller, simpler subset).
Sources
Related Glossary Terms
- String: regex operates on string slices
- Iterator:
.find_iter()and.captures_iter()return iterators - once-cell: Use for compiling regexes once
Keep Reading
- Rust for Python Developers: Python's re module vs Rust's regex crate
- Learn Rust in 2026: common crates every Rust developer reaches for

