I have a Regex with an unknown number of named groups with unknown names. I want to match a string to that regex, and get a HashMap<&str, &str> with the name of the groups as key and the captured strings as value.
How can I do this? Will I have to use regex.captures(str).iter() and then somehow map and filter and collect into a map? Or is there some shortcut?
It is tricky because the regex can have multiple matches, and each capture can be matched multiple times in a single global match.
Maybe something like this (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);
}
That outputs:
{
"y": "2012",
"d": "14",
"m": "03"
}
The code is simple once you realize that the capture names are not available from the Match itself, but from the parent Regex. You have to do the following:
capture_names(), that will be an iterable of Option<&str>.flatten() the iterable, that will remove the None and unwrap the &str values.filter_map() the capture names into a list of tuples (name, value) of type (&str, &str). The filter is needed to remove captures that are not present (thanks to @Anders).collect()! This just works because HashMap<K, V> implements the trait FromIterator<(K, V)>, so an iterator of (&str, &str) collects into a HasMap<&str, &str>.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With