正则表达式
问题
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 基于有限自动机实现,保证 时间复杂度。环视需要回溯引擎,最坏情况为指数时间。如需环视功能,可使用 fancy-regex crate(基于回溯引擎,不保证线性时间)。
Q2: Regex 是线程安全的吗?
答案:
是的。Regex 实现了 Send + Sync,可以安全地在多线程间共享(如放入 static 或 Arc)。内部使用线程本地缓存优化性能。