外观
第 4 节:regex——正则表达式
一句话:String::contains/find 只能找"固定文字";要匹配"模式"(电话号码、邮箱、文件名规则),用正则。regex 是 Rust 最主流的正则库,编译期检查语法、线性时间匹配(不像某些语言会灾难性回溯)。
安装
bash
cargo add regex基本用法:编译一次,反复用 ⭐
rust
use regex::Regex;
// 编译一次(费用高),存起来反复用
let phone = Regex::new(r"1[3-9]\d{9}").expect("正则写错了");铁律:正则要"编译一次、反复用"——Regex::new 开销不小,别放进循环里每轮编译。
四大操作 ⭐
1. 有没有:is_match
rust
let text = "我的电话是 13812345678";
phone.is_match(text); // true2. 第一个:find
rust
if let Some(found) = phone.find(text) {
println!("{}", found.as_str()); // 13812345678
}3. 全部:captures_iter(还能取捕获组)
rust
let email = Regex::new(r"(\w+)@(\w+)\.(\w+)").expect("正则写错了");
let text = "联系我:ferris@rust.cn";
for cap in email.captures_iter(text) {
println!("用户名:{} 域名:{}", &cap[1], &cap[2]);
}
// 用户名:ferris 域名:rustcap[0] 是整个匹配,cap[1]/cap[2]… 是括号捕获组(正则里 (...) 就是"我要提取这段")。
4. 替换:replace / replace_all
rust
let masked = phone.replace_all(text, "****");
// "我的电话是 ****"校验输入的经典姿势:锚定 ⭐
rust
let integer = Regex::new(r"^\d+$").expect("正则写错了");
integer.is_match("42"); // true
integer.is_match("4a2"); // false^(开头)和 $(结尾)把匹配"钉死"在整串上——否则 is_match("4a2") 会在中间的 4 上匹配成功。做输入校验,几乎总是要 ^...$。
常见误用与坑
- 忘了
^...$:is_match默认"包含匹配"——校验"必须是整数"却匹配出"含数字"的子串,是头号坑 Regex::new在循环里:编译开销大,拿到循环外- 转义地狱:正则里
\d在 Rust 字符串里要写成\\d——用原生字符串r"..."(本书示例全部如此),省一层转义 - 捕获组索引越界:
cap[2]但正则只有一组 → panic。先用cap.get(2)判空 find和matches的返回值:find给Option<Match>;要"全部"用find_iter/captures_iter——没有"全匹配列表"这种一次拿完的 API- 中文匹配:
\w默认不匹配中文;匹配任意字符用.(regex 的.匹配 Unicode 字符)