In the book The Practice of Programming, there's a short snippet of C code that implements a regex matcher. Brian W Kernighan has expanded on that chapter and published it online at https://www.cs.princeton.edu/courses/archive/spr09/cos333/beautiful.html
Robs C code relies on the '\0' sentinels for length matching, but that won't work in Rust. So my port of the code ends up with lots of length checks.
I use slices to byte arrays to simplify the task a bit, instead of supporting utf-8 encoded strings.
The implementation consists of three functions re_match, match_here and match_star. I use ranges for iterating over the slices.
// Search for regex anywhere in the text.
fn re_match(regex: &[u8], text: &[u8]) -> bool {
if regex.len() > 0 && regex[0] == b'^' {
return match_here(®ex[1..], &text);
}
// We need to check even if text is empty
if match_here(regex, text) {
return true
}
for i in 0..text.len() {
if match_here(regex, &text[i..]) {
return true
}
}
false
}
// Search for regex at beginning of text
fn match_here(regex: &[u8], text: &[u8]) -> bool {
if regex.len() == 0 {
return true;
}
if regex.len() > 1 && regex[1] == b'*' {
return match_star(regex[0], ®ex[2..], text);
}
if regex.len() == 1 && regex[0] == b'$' {
return text.len() == 0;
}
if text.len() > 0 && (regex[0] == b'.' || regex[0] == text[0]) {
return match_here(®ex[1..], &text[1..]);
}
false
}
// Search for c* regex at beginning of text.
fn match_star(c: u8, regex: &[u8], text: &[u8]) -> bool {
if match_here(regex, text) {
return true;
}
let mut i = 0;
while i < text.len() && (text[i] == c || c == b'.') {
if match_here(regex, &text[i..]) {
return true;
}
i += 1;
}
false
}
Question
- How can I rewrite these kind of functions to not need so many length checks?
- META: Should I use iterators instead of slices as parameters? When choose one over the other?