在Rust中用正则表达式捕获单行内的多个复杂元组实例
Rust日志中元组的正则匹配方案
问题场景
需要从如下格式的日志中捕获所有(u64, Option<u64>)格式的元组:
[2025-01-01T08:17:29.791951550Z INFO] Values: [(311154184, Some(389971313710868251)), (311154187, Some(389967898428572732)), (311154182, Some(389971313710868251)), (311154174, Some(389971313710868251)), (311154178, Some(389971313710868251)), (311154197, Some(389811146843151022)), (311154171, Some(389971313710868251)), (311154167, Some(389971313710868251)), (311154185, Some(389967898428572732)), (311154168, Some(389971313710868251)), (311154191, Some(389967898428572732)), (311154196, Some(389811259875653181)), (311154199, Some(0)), (311154192, Some(389967898428572732)), (311154172, Some(389971313710868251)), (311154181, Some(389971313710868251)), (311154177, Some(389971313710868251)), (311154176, Some(389971313710868251)), (311154179, Some(389971313710868251)), (311154183, Some(389971313710868251)), (311154186, Some(389967898428572732)), (311154175, Some(389971313710868251)), (311154173, Some(389971313710868251)), (311154180, Some(389971313710868251)), (311154190, Some(389967898428572732)), (311154170, Some(389971313710868251)), (311154165, None), (311154189, Some(389967898428572732)), (311154169, Some(389971313710868251)), (311154166, None), (311154195, Some(389967898428572732)), (311154198, Some(287087126717485928)), (311154193, Some(389967898428572732)), (311154188, Some(389967898428572732)), (311154194, Some(389967898428572732))]
元组分为两种格式:
(311154170, Some(389971313710868251))(311154165, None)
原正则的问题
你之前写的((\((\d+), (Some\((\d+)\)|None\)), )+)存在两个核心问题:
- 重复捕获组(
+修饰的组)在Rust的regexcrate中只会保留最后一次匹配的结果,无法捕获所有元组。 - 正则末尾多余的逗号和空格匹配,导致最后一个元组无法被匹配(最后一个元组后无逗号)。
正确的正则表达式
直接匹配单个元组,再通过全局匹配获取所有结果:
\((\d+),\s+(Some\((\d+)\)|None)\)
各部分解释:
\(:匹配元组的左括号(\d+):捕获第一个u64类型的数字,\s+:匹配逗号和任意数量的空白字符(兼容日志中的空格)(Some\((\d+)\)|None):捕获第二个元素,分为两种情况:Some\((\d+)\):匹配Some(数字)格式,其中(\d+)捕获内部的u64数字None:直接匹配None
\):匹配元组的右括号
Rust代码实现
- 在
Cargo.toml中添加依赖:
[dependencies] regex = "1.10"
- 编写解析代码:
use regex::Regex; fn main() { let log_content = r#"[2025-01-01T08:17:29.791951550Z INFO] Values: [(311154184, Some(389971313710868251)), (311154187, Some(389967898428572732)), (311154182, Some(389971313710868251)), (311154174, Some(389971313710868251)), (311154178, Some(389971313710868251)), (311154197, Some(389811146843151022)), (311154171, Some(389971313710868251)), (311154167, Some(389971313710868251)), (311154185, Some(389967898428572732)), (311154168, Some(389971313710868251)), (311154191, Some(389967898428572732)), (311154196, Some(389811259875653181)), (311154199, Some(0)), (311154192, Some(389967898428572732)), (311154172, Some(389971313710868251)), (311154181, Some(389971313710868251)), (311154177, Some(389971313710868251)), (311154176, Some(389971313710868251)), (311154179, Some(389971313710868251)), (311154183, Some(389971313710868251)), (311154186, Some(389967898428572732)), (311154175, Some(389971313710868251)), (311154173, Some(389971313710868251)), (311154180, Some(389971313710868251)), (311154190, Some(389967898428572732)), (311154170, Some(389971313710868251)), (311154165, None), (311154189, Some(389967898428572732)), (311154169, Some(389971313710868251)), (311154166, None), (311154195, Some(389967898428572732)), (311154198, Some(287087126717485928)), (311154193, Some(389967898428572732)), (311154188, Some(389967898428572732)), (311154194, Some(389967898428572732))]"#; // 编译正则表达式 let re = Regex::new(r"\((\d+),\s+(Some\((\d+)\)|None)\)").unwrap(); // 捕获所有匹配项并转换为目标类型 let tuples: Vec<(u64, Option<u64>)> = re.captures_iter(log_content) .filter_map(|cap| { // 解析第一个u64 let first = cap.get(1)?.as_str().parse().ok()?; // 处理第二个元素:Some或None let second = match cap.get(2)?.as_str() { "None" => None, _ => cap.get(3)?.as_str().parse().ok() }; Some((first, second)) }) .collect(); // 打印结果验证 for tup in tuples { println!("{:?}", tup); } }
代码说明
captures_iter返回所有匹配的捕获组,遍历每个元组的匹配结果。filter_map处理解析过程中的错误(如数字解析失败),只保留有效元组。- 对于
Some类型的匹配,通过第三个捕获组获取内部数字;None则直接返回None。
内容的提问来源于stack exchange,提问作者Bobby Dore
相关产品推荐
相关产品推荐

