use eyre::Result; use regex::{Captures, Regex}; fn compile_pattern(pattern: &str) -> Result { let mut result = String::new(); for c in pattern.chars() { if c == '%' { if let Some(real_result) = result.strip_suffix(r"\\\\") { // We end with two backslashes, so this is an escaped backslash and then an // unescaped wildcard. result = real_result.to_owned(); result.push_str(r"\\(\w*)"); } else if let Some(real_result) = result.strip_suffix(r"\\") { // We end with one backslash, so this is an escaped wildcard. result = real_result.to_owned(); result.push('%'); } else { // We don't end with a backslash, so this is an unescaped wildcard. result.push_str(r"(\w*)"); } } else { result.push_str(®ex::escape(&c.to_string())); } } Ok(Regex::new(&result)?) } pub fn r#match<'a>(pattern: &str, text: &'a str) -> Result>> { Ok(compile_pattern(pattern)?.captures(text)) } #[cfg(test)] mod test { use super::*; type R = Result<()>; #[test] fn pattern_backslashes() -> R { let test_case = compile_pattern(r"the\%weird\\%pattern\\")?; assert_eq!(test_case.to_string(), r"the%weird\\(\w*)pattern\\\\"); let hell = compile_pattern(r"\\\\%")?; assert_eq!(hell.to_string(), r"\\\\\\(\w*)"); Ok(()) } }