stix_matcher/
pattern_ops.rs1use regex::Regex;
4
5pub fn like_matches(value: &str, pattern: &str) -> bool {
11 let mut regex = String::with_capacity(pattern.len() * 2 + 2);
12 regex.push('^');
13 for ch in pattern.chars() {
14 match ch {
15 '%' => regex.push_str(".*"),
16 '_' => regex.push('.'),
17 other => regex.push_str(®ex::escape(&other.to_string())),
18 }
19 }
20 regex.push('$');
21 match Regex::new(®ex) {
22 Ok(re) => re.is_match(value),
23 Err(_) => false,
24 }
25}
26
27pub fn regex_matches(value: &str, pattern: &str) -> bool {
32 match Regex::new(pattern) {
33 Ok(re) => re.is_match(value),
34 Err(_) => false,
35 }
36}
37
38#[cfg(test)]
39mod tests {
40 use super::*;
41
42 #[test]
43 fn like_percent_matches_any_run() {
44 assert!(like_matches("foobar.evil.example", "%.evil.example"));
45 assert!(!like_matches("foobar.good.example", "%.evil.example"));
46 }
47
48 #[test]
49 fn like_underscore_matches_single_char() {
50 assert!(like_matches("cat", "c_t"));
51 assert!(!like_matches("coat", "c_t"));
52 }
53
54 #[test]
55 fn like_escapes_regex_metachars() {
56 assert!(like_matches("a.b", "a.b"));
58 assert!(!like_matches("axb", "a.b"));
59 }
60
61 #[test]
62 fn matches_uses_regex() {
63 assert!(regex_matches("invoice12", "invoice[0-9]+"));
64 assert!(!regex_matches("invoice", "invoice[0-9]+"));
65 }
66
67 #[test]
68 fn invalid_regex_does_not_match() {
69 assert!(!regex_matches("anything", "("));
70 }
71}