diff --git a/src/bin/10_regular_expression_matching.rs b/src/bin/10_regular_expression_matching.rs new file mode 100644 index 0000000..6354bfb --- /dev/null +++ b/src/bin/10_regular_expression_matching.rs @@ -0,0 +1,101 @@ +fn main() { + let matcher = RegexMatcher::new(String::from(".*")); + println!("{}", matcher.match_str(String::from("abaaaddddcccd"))); + println!(); + println!("{}", matcher.match_str(String::from("abcd"))); +} + +// TODO: improve runtime +pub fn is_match(s: String, p: String) -> bool { RegexMatcher::new(p).match_str(s) } + +#[derive(Debug, Clone)] +enum Pattern { + ZeroOrMore(char), + SameAs(String), + AnyChar, + ZeroOrMoreAny +} + + +struct RegexMatcher { + patterns: Vec +} + +impl RegexMatcher { + fn new(p: String) -> RegexMatcher { + let mut patterns: Vec = Vec::new(); + let mut buf: String = String::new(); + let mut is_zero_or_more = false; + for c in p.chars().rev() { + match c { + '*' => { + is_zero_or_more = true; + } + '.' => { + if !buf.is_empty() { + patterns.push(Pattern::SameAs(buf.clone())); + buf.clear(); + } + if is_zero_or_more { + patterns.push(Pattern::ZeroOrMoreAny); + is_zero_or_more = false; + } else { + patterns.push(Pattern::AnyChar); + } + } + _ => { + if is_zero_or_more { + if !buf.is_empty() { + patterns.push(Pattern::SameAs(buf.clone())); + buf.clear(); + } + patterns.push(Pattern::ZeroOrMore(c)); + is_zero_or_more = false; + } else { + buf.insert(0, c); + } + } + } + } + if !buf.is_empty() { patterns.push(Pattern::SameAs(buf)); } + patterns.reverse(); + return Self { patterns }; + } + + fn match_str(&self, s: String) -> bool { Self::match_patterns(&s, &self.patterns) } + + fn match_patterns(s: &str, patterns: &[Pattern]) -> bool { + if patterns.is_empty() { return s.is_empty(); } + return match &patterns[0] { + Pattern::SameAs(str) => { + if str.len() > s.len() || str != &s[0..str.len()] { return false; } + Self::match_patterns(&s[str.len()..], &patterns[1..]) + } + Pattern::AnyChar => { + if s.len() < 1 { return false; } + Self::match_patterns(&s[1..], &patterns[1..]) + } + Pattern::ZeroOrMore(char) => { + if s.is_empty() { return Self::match_patterns(&s, &patterns[1..]); } + let mut max_length = 0usize; + for c in s.chars() { + if c != *char { break; } + max_length += 1; + } + for length in (0..=max_length).rev() { + let result = Self::match_patterns(&s[length..], &patterns[1..]); + if result { return result; } + } + false + } + Pattern::ZeroOrMoreAny => { + if s.is_empty() { return Self::match_patterns(&s, &patterns[1..]); } + for length in (0..=s.len()).rev() { + let result = Self::match_patterns(&s[length..], &patterns[1..]); + if result { return result; } + } + false + } + } + } +}