regex_map/
string.rs

1/// Associative container where the keys are regular expressions, based on the `regex::RegexSet` data structure.
2pub struct RegexMap<V> {
3    set: regex::RegexSet,
4    values: Vec<V>,
5}
6
7impl<V> RegexMap<V> {
8    /// Create a new `RegexMap` from iterator over (expression, value) pairs, where the expression is `&str`-like.
9    ///
10    /// ```
11    /// use regex_map::RegexMap;
12    ///
13    /// let map = RegexMap::new([
14    ///    ("foo", 1),
15    ///    ("bar", 2),
16    ///    ("foobar", 3),
17    ///    ("^foo$", 4),
18    ///    ("^bar$", 5),
19    ///    ("^foobar$", 6),
20    /// ]);
21    ///
22    /// assert_eq!(map.get("foo").cloned().collect::<Vec<_>>(), vec![1, 4]);
23    /// assert_eq!(map.get("bar").cloned().collect::<Vec<_>>(), vec![2, 5], );
24    /// assert_eq!(map.get("foobar").cloned().collect::<Vec<_>>(), vec![1, 2, 3, 6]);
25    /// assert_eq!(map.get("XXX foo XXX").cloned().collect::<Vec<_>>(), vec![1]);
26    /// assert_eq!(map.get("XXX bar XXX").cloned().collect::<Vec<_>>(), vec![2]);
27    /// ```
28    pub fn new<I, S>(items: I) -> Self
29    where
30        I: IntoIterator<Item = (S, V)>,
31        S: AsRef<str>,
32    {
33        let mut exprs = Vec::new();
34        let mut values = Vec::new();
35        for (expr, value) in items {
36            exprs.push(expr);
37            values.push(value);
38        }
39
40        let set = regex::RegexSet::new(exprs).unwrap();
41        RegexMap { set, values }
42    }
43
44    /// Get an iterator over all values whose regular expression matches the given key.
45    ///
46    /// To get first matching value, use can use `.next()` on the returned iterator:
47    ///
48    /// ```
49    /// use regex_map::RegexMap;
50    ///
51    /// let map = RegexMap::new([
52    ///    ("foo", 1),
53    ///    ("bar", 2),
54    /// ]);
55    ///
56    /// assert_eq!(map.get("foo").next(), Some(&1));
57    /// ```
58    pub fn get(&self, key: &str) -> impl Iterator<Item = &V> {
59        self.set
60            .matches(key)
61            .into_iter()
62            .map(move |i| &self.values[i])
63    }
64
65    /// Check if the given key matches any of the regular expressions.
66    pub fn contains_key(&self, key: &str) -> bool {
67        self.set.is_match(key)
68    }
69}