跳到主要内容

正则表达式

问题

Rust 中如何使用正则表达式?

答案

Rust 标准库不包含正则,使用 regex crate。它基于有限自动机(NFA/DFA),保证线性时间复杂度,不会出现 ReDoS 攻击。

基础用法

use regex::Regex;

fn main() {
// 编译正则(建议复用,避免重复编译)
let re = Regex::new(r"(\d{4})-(\d{2})-(\d{2})").unwrap();

// 匹配检测
assert!(re.is_match("2024-01-15"));

// 捕获组
if let Some(caps) = re.captures("日期: 2024-01-15") {
println!("完整匹配: {}", &caps[0]); // 2024-01-15
println!("年: {}", &caps[1]); // 2024
println!("月: {}", &caps[2]); // 01
println!("日: {}", &caps[3]); // 15
}

// 查找所有匹配
for mat in re.find_iter("2024-01-15 和 2024-06-30") {
println!("找到: {} 位置: {:?}", mat.as_str(), mat.range());
}

// 替换
let result = re.replace_all("日期 2024-01-15", "$1年$2月$3日");
assert_eq!(result, "日期 2024年01月15日");
}

最佳实践:预编译

use std::sync::LazyLock;
use regex::Regex;

// 全局预编译(Rust 1.80+)
static EMAIL_RE: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$").unwrap()
});

fn is_valid_email(email: &str) -> bool {
EMAIL_RE.is_match(email)
}
性能注意

Regex::new() 编译正则的开销较大。在循环中使用时务必预编译,否则性能会很差。


常见面试问题

Q1: Rust 的 regex 为什么不支持环视(lookahead/lookbehind)?

答案

Rust 的 regex crate 基于有限自动机实现,保证 O(n)O(n) 时间复杂度。环视需要回溯引擎,最坏情况为指数时间。如需环视功能,可使用 fancy-regex crate(基于回溯引擎,不保证线性时间)。

Q2: Regex 是线程安全的吗?

答案

是的。Regex 实现了 Send + Sync,可以安全地在多线程间共享(如放入 staticArc)。内部使用线程本地缓存优化性能。

相关链接