Regular Expressions in Rust with Examples: In Practice

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Regular Expressions in Rust with Examples: In Practice

\n\n

Regular expressions (regex) are a powerful tool for working with text. In Rust, despite its strong typing and focus on safety, working with regular expressions is implemented efficiently and conveniently thanks to the regex crate. In this article, we will break down how to use regular expressions in Rust in practice: from installation to complex string processing scenarios.

\n\n

We will cover the main operations: searching, extraction, replacement, and validation. All code examples are written in Rust and ready to use.

\n\n

Installing and Adding the regex Crate

\n\n

To work with regular expressions in Rust, a third-party but very popular crate called regex is used. It is not part of the standard library, so it needs to be added to the project.

\n\n

Add the dependency to the Cargo.toml file:

\n\n
[dependencies]\nregex = "1"
\n\n

After that, you can import the main types in your code:

\n\n
use regex::Regex;
\n\n

The regex crate compiles the regular expression into a finite state machine, which ensures high performance. Pattern compilation errors are caught at runtime (via Result), making the code reliable.

\n\n

Basics: Searching for Matches in a String

\n\n

The simplest way to check if a string matches a pattern is to use the is_match method. Let's look at an example of checking for an email address in text.

\n\n
use regex::Regex;\n\nfn main() {\n    let re = Regex::new(r"\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b").unwrap();\n    let text = "Contact us at support@example.com.";\n\n    if re.is_match(text) {\n        println!("Email found!");\n    } else {\n        println!("Email not found.");\n    }\n}
\n\n

The Regex::new method takes a pattern string and returns a Result. unwrap() is used here for simplicity, but in production code, errors should be handled properly.

\n\n

To find all matches, use the find_iter method, which returns an iterator over Match objects:

\n\n
use regex::Regex;\n\nfn main() {\n    let re = Regex::new(r"\\d+").unwrap();\n    let text = "Prices: 100, 250 and 500 rubles.";\n\n    for mat in re.find_iter(text) {\n        println!("Found number: {}", mat.as_str());\n    }\n}
\n\n

This code will output:

\n\n
Found number: 100\nFound number: 250\nFound number: 500
\n\n

Data Extraction Using Capturing Groups

\n\n

Capturing groups allow you to extract not just the entire match, but its individual parts. For example, parsing a date in the "dd-mm-yyyy" format.

\n\n
use regex::Regex;\n\nfn main() {\n    let re = Regex::new(r"(\\d{2})-(\\d{2})-(\\d{4})").unwrap();\n    let text = "Today is 15-03-2024.";\n\n    if let Some(caps) = re.captures(text) {\n        println!("Day: {}", &caps[1]);\n        println!("Month: {}", &caps[2]);\n        println!("Year: {}", &caps[3]);\n    }\n}
\n\n

Group indexing starts at 1 (group 0 is the entire match). The captures method returns Option<Captures>. If a match is found, we can access the groups by index.

\n\n

To extract all occurrences with groups, use captures_iter:

\n\n
use regex::Regex;\n\nfn main() {\n    let re = Regex::new(r"(\\w+)@(\\w+)\\.(\\w+)").unwrap();\n    let text = "emails: user@host.com, admin@site.org";\n\n    for caps in re.captures_iter(text) {\n        println!("Login: {}, domain: {}, zone: {}", &caps[1], &caps[2], &caps[3]);\n    }\n}
\n\n

This approach is indispensable when parsing logs, configuration files, or extracting structured data from unstructured text.

\n\n

Text Replacement by Pattern

\n\n

The regex crate provides methods for text replacement. The replace method replaces the first match, and replace_all replaces all matches.

\n\n
use regex::Regex;\n\nfn main() {\n    let re = Regex::new(r"\\bRust\\b").unwrap();\n    let text = "Rust is great. I love Rust!";\n    let result = re.replace_all(text, "Python");\n    println!("{}", result);\n}
\n\n

This code will output:

\n\n
Python is great. I love Python!
\n\n

You can also use backreferences in the replacement string to refer to captured groups:

\n\n
use regex::Regex;\n\nfn main() {\n    let re = Regex::new(r"(\\w+)@(\\w+)\\.(\\w+)").unwrap();\n    let text = "user@host.com";\n    let result = re.replace(text, "$1 at $2 dot $3");\n    println!("{}", result);\n}
\n\n

This will output:

\n\n
user at host dot com
\n\n

String Validation

\n\n

Regular expressions are often used for input validation. For example, checking the correctness of a phone number or password strength.

\n\n
use regex::Regex;\n\nfn validate_phone(phone: &str) -> bool {\n    let re = Regex::new(r"^\\+?[1-9]\\d{1,14}$").unwrap();\n    re.is_match(phone)\n}\n\nfn main() {\n    let phone1 = "+71234567890";\n    let phone2 = "12345";\n    println!("{} is valid: {}", phone1, validate_phone(phone1));\n    println!("{} is valid: {}", phone2, validate_phone(phone2));\n}
\n\n

This example checks if the string matches the international phone number format (E.164).

\n\n

Performance and Safety Tips

\n\n

When working with regular expressions in Rust, it's important to remember a few key points:

\n\n
    \n
  • Compile once, use many times: Creating a Regex object is a relatively expensive operation. If you use the same pattern repeatedly, create the object once and reuse it.
  • \n
  • Avoid catastrophic backtracking: Although the regex crate uses a finite automaton and is not prone to catastrophic backtracking like some other regex engines, complex patterns can still be slow.
  • \n
  • Use raw string literals: Using r"..." avoids the need to escape backslashes, making patterns more readable.
  • \n
  • Handle errors: Always handle the Result returned by Regex::new, especially if the pattern comes from user input.
  • \n
\n\n

Conclusion

\n\n

Regular expressions in Rust are a powerful and efficient tool for text processing. The regex crate provides a rich API for searching, extracting, replacing, and validating strings. Despite the need to add an external dependency, the performance and safety of this crate make it the standard choice for working with regular expressions in the Rust ecosystem.

\n\n

We've covered the basic operations: checking for matches, extracting data using groups, replacing text, and validating input. These examples will help you get started with using regular expressions in your Rust projects.

Blogs

Book Recommendations