Using Regular Expressions in Rust with the regex Crate

The regex crate gives Rust full support for regular expressions. It lets you search, validate, extract, and replace text using familiar patterns just like in JavaScript, Python, or other languages.

I found myself reaching for regex when parsing logs in a CLI tool. Rust’s approach is different: regexes are compiled ahead of time, which makes them fast and safe. It also means your pattern is validated at compile time, so you catch typos early instead of at runtime.

This post shows you how to use regex to match patterns, capture groups, test validity, and perform text replacement all in a way that is fast, safe, and reliable.

Add regex to Your Project

In your Cargo.toml:

[dependencies]
regex = "1"

This gives you access to everything from basic matching to complex pattern parsing.

A Simple Match

To check if a pattern exists in a string:

use regex::Regex;

fn main() {
    let re = Regex::new(r"\d+").unwrap();
    let text = "User ID: 12345";

    if re.is_match(text) {
        println!("Found a number!");
    }
}
  • \d+ matches one or more digits
  • Use r”” for raw strings so you do not need to escape every backslash

Finding Matches

To extract matching values:

let re = Regex::new(r"\d+").unwrap();
let text = "ID: 42, Code: 501";

for number in re.find_iter(text) {
    println!("Found: {}", number.as_str());
}

Use this to pull values from logs, CSVs, or unstructured text.

Capturing Groups

You can name groups and extract them:

let re = Regex::new(r"Name: (?P<name>\w+), Age: (?P<age>\d+)").unwrap();
let text = "Name: Alice, Age: 30";

if let Some(caps) = re.captures(text) {
    let name = &caps["name"];
    let age = &caps["age"];
    println!("Name: {}, Age: {}", name, age);
}

Group syntax:

  • (…) = numbered group
  • (?P<name>…) = named group

Validating Input

Regex is useful for checking if user input is valid:

let email_re = Regex::new(r"^[\w\.-]+@[\w\.-]+\.\w+$").unwrap();

let email = "[email protected]";

if email_re.is_match(email) {
    println!("Valid email!");
} else {
    println!("Invalid email.");
}

This is much safer than manually checking characters.

Replacing Text

To replace matches:

let re = Regex::new(r"\d+").unwrap();
let result = re.replace_all("Cost: 50, Tax: 5", "X");
println!("{}", result);  // Output: Cost: X, Tax: X

You can also use captured values in replacements:

let re = Regex::new(r"(\d+)").unwrap();
let result = re.replace_all("Year: 2025", |caps: ®ex::Captures| {
    let num: i32 = caps[1].parse().unwrap();
    (num + 1).to_string()
});
println!("{}", result);  // Year: 2026

This is great for modifying numbers or formatting content.

Performance Tip

Compile your regex once and reuse it:

lazy_static::lazy_static! {
    static ref RE: Regex = Regex::new(r"\d+").unwrap();
}

You will need to add lazy_static to your dependencies. This avoids compiling the pattern every time.

Common Patterns

  • Email: r”^[\w\.-]+@[\w\.-]+\.\w+$”
  • Phone: r”\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}”
  • Date: r”\d{4}-\d{2}-\d{2}”

You can copy-paste many patterns from other languages, as they mostly work the same.

Summary

The regex crate gives Rust rich and safe support for pattern matching and text parsing. You can use it to validate input, search logs, extract fields, or clean up messy data. It compiles your patterns and checks them early, so your tools are both safe and fast.