在 Rust 中将正则表达式捕获转换为 HashMap?

Convert regex Captures into HashMap in Rust?

我有一个 Regex,其中包含数量未知且名称未知的命名组。我想将一个字符串与该正则表达式匹配,并得到一个 HashMap<&str, &str>,其中组名作为键,捕获的字符串作为值。

我该怎么做?我是否必须使用 regex.captures(str).iter() 然后以某种方式映射和过滤并收集到地图中?或者有什么捷径?

这很棘手,因为正则表达式可以有多个匹配,并且每个捕获可以在单个全局匹配中匹配多次。

也许是这样的(playground):

fn main() {
    let re = Regex::new(r"(?P<y>\d{4})-(?P<m>\d{2})-(?P<d>\d{2})").unwrap();
    let text = "2012-03-14";
    let caps = re.captures(text).unwrap();
    let dict: HashMap<&str, &str> = re
        .capture_names()
        .flatten()
        .filter_map(|n| Some((n, caps.name(n)?.as_str())))
        .collect();
    println!("{:#?}", dict);
}

输出:

{
    "y": "2012",
    "d": "14",
    "m": "03"
}

一旦您意识到捕获名称无法从 Match 本身获得,而是从父级 Regex 获得,代码就很简单了。您必须执行以下操作:

  1. 调用 capture_names(),这将是 Option<&str> 的可迭代对象。
  2. flatten() 可迭代对象,它将删除 Noneunwrap &str 值。
  3. filter_map() 将名称捕获到类型 (&str, &str) 的元组列表 (名称,值) 中。 filter 需要删除不存在的捕获(感谢@Anders)。
  4. collect()!这之所以有效,是因为 HashMap<K, V> 实现了特征 FromIterator<(K, V)>,因此 (&str, &str) 的迭代器收集到 HasMap<&str, &str>.

如果您有多个捕获,您可以将它们收集到这样的列表中:

let all: Vec<HashMap<&str, &str>> = re
    .captures_iter("2012-01-12 , 2013-07-11 , 2014-09-14")
    .map(|caps| {
        re.capture_names()
            .map(|o| o.and_then(|n| Some((n, caps.name(n)?.as_str()))))
            .flatten()
            .collect()
    })
    .collect();

println!("{:#?}", all);