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