regex matching

This commit is contained in:
Dan Frumin 2024-06-08 22:49:30 +02:00
parent e6c9c27b33
commit 009b3cb261
1 changed files with 98 additions and 15 deletions

View File

@ -8,6 +8,9 @@ enum RegExp {
Kleene(Box<RegExp>),
}
// Derivatives
fn is_nullable (r : &RegExp) -> bool {
match r {
RegExp::Epsilon => true,
@ -43,22 +46,102 @@ fn derivative(r : &RegExp, a : char) -> RegExp {
}
}
fn regexp_match(r : RegExp, s : &String) -> bool {
let chrs = s.chars();
let mut rs : RegExp = r;
for c in chrs {
println!("Computing der({:?}, {:?}) ...", rs, c);
rs = derivative(&rs, c);
impl RegExp {
fn match_string(self : RegExp, s : &String) -> bool {
let chrs = s.chars();
let mut rs : RegExp = self;
for c in chrs {
rs = derivative(&rs, c);
}
is_nullable(&rs)
}
println!("Result: {:?}", rs);
is_nullable(&rs)
}
fn main() {
let r1 = RegExp::Concat(Box::new( RegExp::Char('a')), Box::new( RegExp::Char('b')));
let r2 = RegExp::Kleene(Box::new(r1.clone()));
let r3 = RegExp::Concat(Box::new(RegExp::Union(Box::new(r1.clone()), Box::new(RegExp::Char('c')))), Box::new(r2.clone()));
let inp = String::from("c");
let res = regexp_match(r3.clone(), &inp);
println!("match {:?}, {:?} = {:?}", r3, inp, res);
use std::iter::Peekable;
use std::str::Chars;
enum ParseError {
EatMismatch(char),
EndOfString,
Heh
}
fn eat(str : &mut Peekable<Chars>, c : char) -> Result<char, ParseError> {
match str.next_if(|&x| x == c) {
Some(c) => Ok(c),
None => Err(ParseError::EatMismatch(c))
}
}
fn term(str : &mut Peekable<Chars>) -> Result<RegExp, ParseError> {
let mut result = RegExp::Epsilon;
loop {
match str.peek() {
Some(&c) if (c != ')') & (c != '|') => {
let r = factor(str)?;
result = RegExp::Concat(Box::new(result), Box::new(r))
},
_ => { break; }
}
}
Ok(result)
}
fn regex(str : &mut Peekable<Chars>) -> Result<RegExp, ParseError> {
let t = term(str)?;
match str.peek() {
Some('|') => {
let _ = eat(str, '|');
let r = regex(str)?;
Ok(RegExp::Union(Box::new(t), Box::new(r)))
},
_ => Ok(t)
}
}
fn factor(str : &mut Peekable<Chars>) -> Result<RegExp, ParseError> {
let mut result = base(str)?;
loop {
match str.peek() {
Some(&c) if (c == '*') => {
let _ = eat(str, '*')?;
result = RegExp::Kleene(Box::new(result))
},
_ => { break; }
}
}
Ok(result)
}
fn base(str : &mut Peekable<Chars>) -> Result<RegExp, ParseError> {
match str.peek() {
Some(&c) => {
if c == '(' {
let _ = eat(str, '(')?;
let r = regex(str)?;
let _ = eat(str, ')')?;
Ok(r)
} else {
let _ = eat(str, c)?;
Ok(RegExp::Char(c))
}
},
None => Err(ParseError::EndOfString)
}
}
impl RegExp {
fn from(str : String) -> RegExp {
match regex(&mut str.chars().peekable()) {
Ok(r) => r,
_ => panic!("Ooooo")
}
}
}
fn main() {
let s1 = RegExp::from(String::from("(ab|c)(ab)*"));
let inp = String::from("abab");
let res = s1.clone().match_string(&inp);
println!("match {:?}, {:?} = {:?}", s1, inp, res);
}