pub fn like_match(s: &str, pattern: &str) -> bool {
let s_chars: Vec<char> = s.chars().collect();
let p_chars: Vec<char> = pattern.chars().collect();
like_match_chars(&s_chars, &p_chars)
}
fn like_match_chars(s: &[char], p: &[char]) -> bool {
let (mut si, mut pi) = (0usize, 0usize);
let mut star_pi: Option<usize> = None;
let mut star_si = 0usize;
while si < s.len() {
if pi < p.len() && p[pi] == '%' {
star_pi = Some(pi);
star_si = si;
pi += 1;
} else if pi < p.len() && (p[pi] == '_' || p[pi] == s[si]) {
si += 1;
pi += 1;
} else if let Some(spi) = star_pi {
star_si += 1;
si = star_si;
pi = spi + 1;
} else {
return false;
}
}
while pi < p.len() && p[pi] == '%' {
pi += 1;
}
pi == p.len()
}
#[cfg(test)]
mod tests {
use super::like_match;
#[test]
fn test_basic_wildcards() {
assert!(like_match("hello", "hello"));
assert!(like_match("hello", "%llo"));
assert!(like_match("hello", "h%o"));
assert!(like_match("hello", "h_llo"));
assert!(like_match("hello", "%"));
assert!(like_match("", "%"));
assert!(like_match("hello", "h%l%o"));
assert!(!like_match("hello", "world"));
assert!(!like_match("hello", "hell"));
assert!(!like_match("hello", "_ello_"));
}
#[test]
fn test_literal_metacharacters() {
assert!(like_match("file.txt", "file%"));
assert!(like_match("file.txt", "file.txt"));
assert!(!like_match("fileXtxt", "file.txt")); assert!(like_match("test(1)", "%(%"));
assert!(like_match("a+b", "a+b"));
assert!(like_match("a[b]", "a[b]"));
}
#[test]
fn test_case_sensitive() {
assert!(like_match("Hello", "Hello"));
assert!(!like_match("Hello", "hello"));
assert!(!like_match("HELLO", "%llo"));
}
#[test]
fn test_many_percent_no_blowup() {
let s = "a".repeat(50);
assert!(like_match(&s, "%a%a%a%a%a%a%a%a%a%a%"));
let s2 = "a".repeat(49) + "b";
assert!(!like_match(&s2, "%a%a%a%a%a%a%a%a%a%a%a%c"));
}
}