regex_set_replacer.rs
1 use regex::{Regex, RegexSet}; 2 3 #[derive(Debug)] 4 pub struct RegexSetReplacer { 5 regex_set: RegexSet, 6 rules: Vec<(Regex, String)>, 7 } 8 9 impl RegexSetReplacer { 10 pub fn new(rules: Vec<(Regex, String)>) -> Self { 11 let regex_set = RegexSet::new(rules.iter().map(|(r, _)| r.as_str())).unwrap(); 12 Self { regex_set, rules } 13 } 14 15 pub fn match_and_replace(&self, haystack: &str) -> Option<RegexSetReplacerMatch> { 16 self.regex_set.matches(haystack).iter().next().map(|idx| { 17 let (regex, replacement) = &self.rules[idx]; 18 let replacement = regex.replace(haystack, replacement).into_owned(); 19 RegexSetReplacerMatch { idx, replacement } 20 }) 21 } 22 } 23 24 #[derive(Debug, Clone, PartialEq, Eq)] 25 pub struct RegexSetReplacerMatch { 26 pub idx: usize, 27 pub replacement: String, 28 } 29 30 #[cfg(test)] 31 mod tests { 32 use super::*; 33 34 #[test] 35 fn regex_set_replacer() { 36 let replacer = RegexSetReplacer::new(vec![ 37 (Regex::new(r"foo(\d+)").unwrap(), "${1}FOO".into()), 38 (Regex::new(r"bar(\d+)").unwrap(), "${1}BAR".into()), 39 ]); 40 41 let RegexSetReplacerMatch { idx, replacement } = 42 replacer.match_and_replace("foo42").unwrap(); 43 assert_eq!(idx, 0); 44 assert_eq!(replacement, "42FOO"); 45 46 let RegexSetReplacerMatch { idx, replacement } = 47 replacer.match_and_replace("bar1337").unwrap(); 48 assert_eq!(idx, 1); 49 assert_eq!(replacement, "1337BAR"); 50 51 assert_eq!(replacer.match_and_replace("test"), None); 52 } 53 }