const R: usize = 256;
pub struct BoyerMoore {
right: [usize; R],
pat: String,
}
fn char_at(s: &str, d: usize) -> usize {
s.as_bytes()[d] as usize
}
impl BoyerMoore {
pub fn new(pat: String) -> Self {
let m = pat.len();
let mut right = [0; R];
for j in 0..m {
right[char_at(&pat, j)] = j + 1;
}
BoyerMoore { pat, right }
}
pub fn search(&self, txt: &str) -> usize {
let n = txt.len();
let m = self.pat.len();
let mut skip: usize;
let mut i = 0;
if n < m {
return n;
}
let end = n - m;
while i <= end {
skip = 0;
for j in (0..m).rev() {
let p = char_at(txt, i + j);
if char_at(&self.pat, j) != p {
if self.is_left_of_pos(p, j) {
skip = j + 1 - self.right[p];
assert!(skip >= 1, "is_left_of_pos 计算错误:{},{}", skip, j);
} else {
skip = 1;
}
break;
}
}
if skip == 0 {
return i;
}
i += skip;
}
n
}
pub fn is_left_of_pos(&self, c: usize, pos: usize) -> bool {
self.right[c] < pos + 1
}
}
#[cfg(test)]
mod test {
use super::BoyerMoore;
#[test]
fn test() {
let kmp = BoyerMoore::new("abc".to_string());
assert_eq!(kmp.search("ababac"), 6);
assert_eq!(kmp.search("ababcc"), 2);
assert_eq!(kmp.search("ababccababcc"), 2);
assert_eq!(kmp.search("abcbcc"), 0);
assert_eq!(kmp.search("babcbcc"), 1);
assert_eq!(kmp.search("aabcbcc"), 1);
assert_eq!(kmp.search("ab"), 2);
}
}