-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathglob.rs
More file actions
96 lines (84 loc) · 2.54 KB
/
Copy pathglob.rs
File metadata and controls
96 lines (84 loc) · 2.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
/// Match text against any pattern. Patterns must be pre-lowercased at load time; the input is lowercased here.
pub fn glob_match_any(patterns: &[String], text: &str) -> bool {
if patterns.is_empty() {
return false;
}
let text_lower = text.to_lowercase();
let text_bytes = text_lower.as_bytes();
for pattern in patterns {
if glob_match_impl(pattern.as_bytes(), text_bytes) {
return true;
}
}
false
}
/// Two-pointer glob matcher. Both pattern and text must already be lowercased.
pub fn glob_match_impl(pattern: &[u8], text: &[u8]) -> bool {
let mut pi = 0usize;
let mut ti = 0usize;
let mut star_pi = usize::MAX;
let mut star_ti = 0usize;
while ti < text.len() {
if pi < pattern.len() && (pattern[pi] == b'?' || pattern[pi] == text[ti]) {
pi += 1;
ti += 1;
} else if pi < pattern.len() && pattern[pi] == b'*' {
star_pi = pi;
star_ti = ti;
pi += 1;
} else if star_pi != usize::MAX {
pi = star_pi + 1;
star_ti += 1;
ti = star_ti;
} else {
return false;
}
}
while pi < pattern.len() && pattern[pi] == b'*' {
pi += 1;
}
pi == pattern.len()
}
#[cfg(test)]
mod tests {
use super::*;
fn matches(pattern: &str, text: &str) -> bool {
glob_match_any(&[pattern.to_lowercase()], text)
}
#[test]
fn glob_exact_match() {
assert!(matches("hello", "hello"));
assert!(!matches("hello", "world"));
}
#[test]
fn glob_star_wildcard() {
assert!(matches("*", "anything"));
assert!(matches("*timeout*", "Connection timeout error"));
assert!(matches("*timeout*", "timeout"));
assert!(matches("Error*", "Error: something"));
assert!(!matches("Error*", "some Error"));
}
#[test]
fn glob_question_mark() {
assert!(matches("h?llo", "hello"));
assert!(matches("h?llo", "hallo"));
assert!(!matches("h?llo", "hllo"));
}
#[test]
fn glob_case_insensitive() {
assert!(matches("*NetworkError*", "networkerror in fetch"));
assert!(matches("HELLO", "hello"));
assert!(matches("hello", "HELLO"));
}
#[test]
fn glob_empty_patterns() {
assert!(matches("", ""));
assert!(!matches("", "nonempty"));
assert!(matches("*", ""));
}
#[test]
fn glob_multiple_stars() {
assert!(matches("*a*b*", "xaybz"));
assert!(!matches("*a*b*", "xyz"));
}
}