#[derive(Debug)]
pub struct WildMatch {
pattern: Vec<char>,
match_min_len: usize,
}
impl WildMatch {
pub fn new(pattern: &str) -> WildMatch {
let mut simplified: Vec<char> = Vec::new();
let mut prev_was_star = false;
let mut match_min_len = 0;
for i in pattern.chars() {
if i == '*' {
if !prev_was_star {
simplified.push(i);
}
prev_was_star = true;
} else {
simplified.push(i);
prev_was_star = false;
match_min_len += 1;
}
}
WildMatch {
pattern: simplified,
match_min_len: match_min_len,
}
}
pub fn is_match(&self, input: &str) -> bool {
if self.pattern.len() == 1 && self.pattern[0] == '*' {
return true;
}
let mut pattern_idx = 0;
let mut pattern_len = 0;
let mut wildcard = false;
for input_char in input.chars() {
let pattern_char = self.pattern.get(pattern_idx);
println!("match_min: {}", self.match_min_len);
println!("pattern_len: {}", pattern_len);
if pattern_char.is_none() && pattern_len >= self.match_min_len {
return wildcard;
}
let pattern_char = pattern_char.unwrap();
if pattern_char == &input_char || pattern_char == &'?' {
pattern_idx += 1;
pattern_len += 1;
if wildcard {
wildcard = false;
}
} else if wildcard {
continue;
} else if pattern_char == &'*' {
wildcard = true;
pattern_idx += 1;
} else {
pattern_idx = 0;
pattern_len = 0;
}
}
return self.pattern.get(pattern_idx).is_none() && pattern_len >= self.match_min_len;
}
}
#[cfg(test)]
mod tests {
use super::*;
use ntest::test_case;
#[test_case("**", test_name = "star_star")]
#[test_case("*", test_name = "star")]
#[test_case("*?*", test_name = "star_q_star")]
#[test_case("c*", test_name = "c_star")]
#[test_case("c?*", test_name = "c_q_star")]
#[test_case("???", test_name = "qqq")]
#[test_case("c?t", test_name = "c_q_t")]
#[test_case("cat", test_name = "cat")]
fn is_match(pattern: &str) {
let m = WildMatch::new(pattern);
assert!(m.is_match("cat"));
}
#[test_case("*d*", test_name = "star_d_star")]
#[test_case("*d", test_name = "star_d")]
#[test_case("d*", test_name = "d_star")]
#[test_case("*c", test_name = "star_c")]
#[test_case("?", test_name = "q")]
#[test_case("??", test_name = "q2")]
#[test_case("????", test_name = "q4")]
#[test_case("?????", test_name = "q5")]
#[test_case("*????", test_name = "wild_q_four")]
#[test_case("cats", test_name = "longer")]
#[test_case("cat?", test_name = "longer_q")]
#[test_case("cacat", test_name = "cacat")]
fn no_match(pattern: &str) {
let m = WildMatch::new(pattern);
assert!(!m.is_match("cat"));
}
#[test]
fn longer_string_match() {
let m = WildMatch::new("*cat*");
assert!(m.is_match("d&(*og_cat_dog"));
}
}