Implemented problem 10
This commit is contained in:
parent
5da5a2ca0a
commit
e77be12ebe
1 changed files with 101 additions and 0 deletions
101
src/bin/10_regular_expression_matching.rs
Normal file
101
src/bin/10_regular_expression_matching.rs
Normal file
|
@ -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<Pattern>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RegexMatcher {
|
||||||
|
fn new(p: String) -> RegexMatcher {
|
||||||
|
let mut patterns: Vec<Pattern> = 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue