diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "regexp" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "regexp" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/main.rs b/src/main.rs new file mode 100644 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,148 @@ +use std::collections::{HashMap, HashSet}; + +struct Regexp { + rules: HashMap<(usize, char), HashSet>, + end_states: HashSet +} + +impl Regexp { + pub fn new(pattern: String) -> Self { + println!("> {pattern}"); + let pattern_chars = Vec::from_iter(pattern.chars()); + let mut star = false; + let mut plus = false; + let n = pattern.len(); + let mut states = vec![HashSet::from([n])]; + let mut end_states = HashSet::new(); + let mut rules = HashMap::new(); + + for i in 0..n { + let j = n-i-1; + let c = pattern_chars[j]; + let k = states.len()-1; + if c == '*' { + star = true; + continue; + } + if c == '+' { + plus = true; + continue; + } + if star { + states[k].insert(j); + println!("{j}: {:?}", states[k]); + Regexp::update_rule(&mut rules, j, &pattern_chars, &states[k]); + if states[k].contains(&n) {end_states.insert(j);} + star = false; + } + else if plus { + states[k].insert(j); + println!("{j}: {:?}", states[k]); + Regexp::update_rule(&mut rules, j, &pattern_chars, &states[k]); + if states[k].contains(&n) {end_states.insert(j);} + states.push(HashSet::from([j])); + plus = false; + } + else { + println!("{j}: {:?}", states[k]); + Regexp::update_rule(&mut rules, j, &pattern_chars, &states[k]); + if states[k].contains(&n) {end_states.insert(j);} + states.push(HashSet::from([j])); + } + if j == 0 { + let m = states.len()-1; + println!("99: {:?} (start)", states[m]); + Regexp::update_rule(&mut rules, 99, &pattern_chars, &states[m]); + if states[m].contains(&n) {end_states.insert(j);} + } + } + + println!("{rules:?}"); + return Regexp {rules, end_states}; + } + + pub fn eval(self, s: String) -> bool { + let mut multistate = HashSet::from([99]); + + for c in s.chars() { + let mut new_multistate = HashSet::new(); + + for state in multistate { + if let Some(x) = self.rules.get(&(state, c)) { + new_multistate = new_multistate.union(&x).map(|&y| y).collect(); + } else if let Some(x) = self.rules.get(&(state, '.')) { + new_multistate = new_multistate.union(&x).map(|&y| y).collect(); + } + } + multistate = new_multistate; + } + + return multistate.iter().any(|x| self.end_states.contains(x)); + } + + fn update_rule(rules: &mut HashMap<(usize, char), HashSet>, pos: usize, pattern: &Vec, values: &HashSet) { + let n = pattern.len(); + + for &target in values.iter() { + println!("pos: {pos}, target: {target}"); + if target == n {continue;} + let c = pattern[target]; + let key = (pos, c); + if !rules.contains_key(&key) {rules.insert(key, HashSet::new());} + match rules.get_mut(&key) { + Some(set) => {set.insert(target);}, + None => {rules.insert(key, HashSet::from([target]));} + }; + } + } + + fn find_previous_letter(s: &String, k: usize) -> Option { + return s[..k].rfind(char::is_alphanumeric); + } + + fn find_next_letter(s: &String, k: usize) -> Option { + return s[k+1..].find(char::is_alphanumeric); + } + + fn find_opening_parenthesis(s: &String, k: usize) -> Option { + let chars: Vec = s.chars().collect(); + let mut i = k; + let mut counter = 1; + + while counter > 0 { + match chars[i] { + '(' => counter -= 1, + ')' => counter += 1, + _ => {} + } + match i.checked_sub(1) { + Some(x) => i = x, + None => return None + } + } + return Some(i); + } +} + +struct Solution {} + +impl Solution { + pub fn is_match(s: String, p: String) -> bool { + let regexp = Regexp::new(p); + + return regexp.eval(s); + } +} + +fn main() { + // println!("{}\n", Solution::is_match(String::from("aa"), String::from("a"))); + // println!("{}\n", Solution::is_match(String::from("aa"), String::from("a*"))); + // println!("{}\n", Solution::is_match(String::from("ab"), String::from(".*"))); + // println!("{}\n", Solution::is_match(String::from("aab"), String::from("a*ab"))); + // println!("{}\n", Solution::is_match(String::from("aab"), String::from("a*b*"))); + println!("{}\n", Solution::is_match(String::from("a"), String::from("a+"))); + println!("{}\n", Solution::is_match(String::from("aa"), String::from("a+"))); + println!("{}\n", Solution::is_match(String::from(""), String::from("a+"))); + println!("{}\n", Solution::is_match(String::from("bb"), String::from("ba+b"))); + println!("{}\n", Solution::is_match(String::from("baaaaab"), String::from("ba+b"))); +}