pub(crate) fn match_str(pattern: &str, input: &str, case_insensitive: bool) -> bool {
let mut p_chars = pattern.chars();
let mut i_chars = input.chars();
while let Some(p_char) = p_chars.next() {
let p_char = if case_insensitive {
p_char.to_ascii_lowercase()
} else {
p_char
};
match p_char {
'*' => {
loop {
match p_chars.clone().peekable().peek() {
Some(&p_char_next) => {
if p_char_next != '*' {
break;
}
p_chars.next();
}
None => {
return true;
}
}
}
let p_str = p_chars.as_str();
let i_str = i_chars.as_str();
for i in 0..i_str.len() {
if match_str(p_str, &i_str[i..], case_insensitive) {
return true;
}
}
return false;
}
'?' => {
if i_chars.next().is_none() {
return false;
}
}
'-' | '_' => match i_chars.next() {
Some(i_char) if i_char == '-' || i_char == '_' => continue,
_ => return false,
},
_ => {
let i_char = match i_chars.next() {
Some(c) if case_insensitive => c.to_ascii_lowercase(),
Some(c) => c,
None => return false,
};
if p_char != i_char {
return false;
}
}
}
}
i_chars.next().is_none()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_match_a() {
assert!(match_str("he?lo", "hello", false));
assert!(match_str("*world", "hello world", false));
assert!(match_str("he*o", "hello", false));
assert!(match_str("he*o", "heo", false));
assert!(match_str("he*o", "heasdfasdfero", false));
assert!(!match_str("h?llo", "hella", false));
assert!(!match_str("hell*o", "hellaaaaa", false));
}
#[test]
fn test_match_b() {
assert!(match_str("He?lo", "hello", true));
assert!(match_str("he*O", "heLLo", true));
assert!(!match_str("He*O", "hello", false));
}
#[test]
fn test_match_c() {
assert!(match_str("*", "anything", false));
assert!(match_str("h*o", "hello", false));
assert!(match_str("h?llo*", "hello world", false));
assert!(match_str("he*l?d*", "he_______l?dworlt", false));
assert!(!match_str("he*l?d", "hello worlt", false));
}
#[test]
fn test_match_d() {
assert!(match_str("he_lo", "he-lo", false));
assert!(match_str("he-lo", "he_lo", false));
assert!(match_str("he*-world", "heLLo_world", false));
assert!(match_str("he*-wor?d", "heLLo_worxd", false));
assert!(match_str("he*-wor*", "heLLo_worxd", false));
assert!(!match_str("he*-wor*q", "heLLo_worxd", false));
}
#[test]
fn test_match_e() {
assert!(match_str("H*o w*d", "hello world", true));
assert!(match_str("H*o w*d", "hello world", true));
assert!(!match_str("H*o w*d", "hello world", true));
}
#[test]
fn test_match_f() {
assert!(match_str("???", "hld", true));
assert!(match_str("???*", "hld", true));
assert!(match_str("???*", "hldfoooo", true));
assert!(match_str("???*.png", "hldfoooo.png", true));
assert!(!match_str("???", "ld", true));
assert!(!match_str("???*.png", "hldfoooo.pn", true));
assert!(!match_str("???.png", "o.png", true));
}
#[test]
fn test_match_g() {
assert!(!match_str("???*.png", "x.png", true));
}
#[test]
fn test_match_h() {
assert!(match_str("-_-_??*.png", "----oo.png", true));
assert!(match_str("-_-_??*.png", "____oo.png", true));
assert!(match_str("-_-_??*.png", "____ooXXX.png", true));
assert!(!match_str("-_-_??*.png", "____o.png", true));
assert!(!match_str("-_-_??.png", "____ooo.png", true));
}
}