Rust Regex Basics
A regex is a pattern that describes the shape of text, instead of one exact spelling. A code might be two letters, then four digits, and a date can be any day at all.
Checking a shape by hand takes work
Two letters, then four digits — checked by hand, one piece at a time:
fn main() {
let code = "AB1234";
let letters = code.chars().take(2).all(|c| c.is_ascii_uppercase());
let digits = code.chars().skip(2).all(|c| c.is_ascii_digit());
let shape_ok = code.len() == 6 && letters && digits;
println!("{} fits the shape: {}", code, shape_ok);
}Build a matcher
Regex::new compiles the pattern text into a matcher.
let re = Regex::new(r"\d+").unwrap();Ask a yes-or-no question
is_match answers true or false. It does not say where the match sits.
let re = Regex::new(r"\d+").unwrap();
println!("{}", re.is_match("order 42"));
println!("{}", re.is_match("no digits"));find gives the first match
find returns a Match. It knows its byte start, its byte end, and its text.
let re = Regex::new(r"\d+").unwrap();
let m = re.find("order 42 today").unwrap();
println!("{}..{} = {}", m.start(), m.end(), m.as_str());Raw strings keep patterns readable
In a normal string, every backslash doubles. A raw string starts with r and keeps the pattern as written.
let normal = Regex::new("\\d{4}-\\d{2}").unwrap();
let raw = Regex::new(r"\d{4}-\d{2}").unwrap();
println!("{}", normal.is_match("2026-10") && raw.is_match("2026-10"));find_iter walks every match
find_iter lends each match in turn. Collect the texts when you need them all.
let re = Regex::new(r"\d+").unwrap();
let found: Vec<&str> = re.find_iter("a1 b22 c333").map(|m| m.as_str()).collect();
println!("{:?}", found);A broken pattern fails at build time
An unclosed ( makes the pattern invalid. Regex::new says so at once, with an Err.
let bad = Regex::new(r"(\d+");
println!("broken pattern is error = {}", bad.is_err());Example
// Cargo.toml: regex = "1"
use regex::Regex;
fn main() {
let re = Regex::new(r"\d+").unwrap();
let log = "user 7 logged in, user 42 logged out";
println!("has digits = {}", re.is_match(log));
let first = re.find(log).unwrap();
println!("first number: {} at bytes {}..{}", first.as_str(), first.start(), first.end());
let all: Vec<&str> = re.find_iter(log).map(|m| m.as_str()).collect();
println!("all numbers = {:?}", all);
}Key points
- Regex: a pattern that describes a shape of text, like "two letters, then three digits"
- A regex matches a shape: any text that fits the shape counts, whatever its exact letters.
- The regex crate is an extra library: add regex = "1" under [dependencies] in Cargo.toml (checked here against version 1.13.1)
- Use Regex::new(pattern) to build a matcher: it returns a Result, because a broken pattern fails at build time
- Use is_match to ask a yes-or-no question, and find to get the first match with its byte start and end
- Write patterns as raw strings, like r"\d+": the backslash stays single, and the pattern stays readable
- The regex crate is the engine inside tools like ripgrep.
In this example, one pattern does three jobs on one log line. is_match answers true: the line holds digits. find locates the first number. It is the 7 at bytes 5 to 6. find_iter then walks the whole line and collects both numbers. The pattern was built once, at the top. Every later call reuses it.
Note
The standard library has no regex.
The regex crate is the usual choice.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Rust Playground
Exercise
What does find return when the text holds no match?