vec_reg_common/
regex.rs

1pub mod vm;
2
3use std::rc::Rc;
4
5use self::vm::CompiledRegexInVm;
6use super::CompiledRegex;
7
8#[derive(Clone)]
9pub enum Regex<T> {
10    /// Like a '^' in ragex. Regex that matches the beginning of the input.
11    Begin,
12    /// Like a '$' in ragex. Regex that matches the end of the input.
13    End,
14    /// Like a `[character class]` in regex. Regex that matches any values that satisfy the given predicate.
15    Satisfy(Rc<dyn Fn(&T) -> bool>),
16    /// Like a `[^character class]` in regex. Regex that matches any values that not satisfy the given predicate.
17    NotSatisfy(Rc<dyn Fn(&T) -> bool>),
18    /// Like a `RS` in regex. Concatenate two regex.
19    Concat(Rc<Regex<T>>, Rc<Regex<T>>),
20    /// Like a `(R)` in regex. Numbered capturing group (submatch).
21    Group(Rc<Regex<T>>),
22    /// Like a `(?<name>R)` in regex. Numbered capturing group (submatch).
23    NamedGroup(String, Rc<Regex<T>>),
24    /// Like a `(?:R)` in regex. Numbered non-capturing group.
25    NonCapturingGroup(Rc<Regex<T>>),
26    /// Like a `R|S` in regex. Regex alternation.
27    Or(Rc<Regex<T>>, Rc<Regex<T>>),
28    /// Like a `?`, `??` in regex. Regex zero or one.
29    ZeroOrOne(Rc<Regex<T>>, bool),
30    /// Like a `*`, `*?` in regex. Regex zero or one.
31    Repeat0(Rc<Regex<T>>, bool),
32    /// Like a `+`, `+?` in regex. Regex one or more.
33    Repeat1(Rc<Regex<T>>, bool),
34    /// Like a `{n}` in regex. Exactly N-times.
35    RepeatN(Rc<Regex<T>>, usize),
36    /// Like a `{n,m}`, `{n,m}?` or `{n,}`, `{n,}?` in regex. n or n+1 or .. m times.
37    RepeatMinMax(Rc<Regex<T>>, usize, Option<usize>, bool),
38}
39
40impl<T> std::fmt::Debug for Regex<T> {
41    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42        match self {
43            Regex::Begin => f.write_str("Begin"),
44            Regex::End => f.write_str("End"),
45            Regex::Satisfy(_) => f.debug_tuple("Satisfy").field(&"<fn>").finish(),
46            Regex::NotSatisfy(_) => f.debug_tuple("NotSatisfy").field(&"<fn>").finish(),
47            Regex::Concat(l, r) => f.debug_tuple("Concat").field(l).field(r).finish(),
48            Regex::Group(r) => f.debug_tuple("Group").field(r).finish(),
49            Regex::NamedGroup(name, r) => f.debug_tuple("NamedGroup").field(name).field(r).finish(),
50            Regex::NonCapturingGroup(r) => f.debug_tuple("NonCaptureGroup").field(r).finish(),
51            Regex::Or(l, r) => f.debug_tuple("Or").field(l).field(r).finish(),
52            Regex::Repeat0(r, greedy) => f.debug_tuple("Repeat0").field(r).field(greedy).finish(),
53            Regex::ZeroOrOne(r, greedy) => {
54                f.debug_tuple("ZeroOrOne").field(r).field(greedy).finish()
55            }
56            Regex::Repeat1(r, greedy) => f.debug_tuple("Repeat1").field(r).field(greedy).finish(),
57            Regex::RepeatN(r, n) => f.debug_tuple("RepeatN").field(r).field(n).finish(),
58            Regex::RepeatMinMax(r, n, m, greedy) => f
59                .debug_tuple("RepeatMinMax")
60                .field(r)
61                .field(n)
62                .field(m)
63                .field(greedy)
64                .finish(),
65        }
66    }
67}
68
69impl<T> std::fmt::Display for Regex<T> {
70    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71        match self {
72            Regex::Begin => write!(f, "^"),
73            Regex::End => write!(f, "$"),
74            Regex::Satisfy(_) => write!(f, "[<fn>]"),
75            Regex::NotSatisfy(_) => write!(f, "[^ <fn>]"),
76            Regex::Concat(l, r) => write!(f, "{}{}", l, r),
77            Regex::Group(r) => write!(f, "({})", r),
78            Regex::NamedGroup(r, name) => write!(f, "(P<{}>{})", name, r),
79            Regex::NonCapturingGroup(r) => write!(f, "(?:{})", r),
80            Regex::Or(l, r) => write!(f, "{}|{}", l, r),
81            Regex::Repeat0(r, greedy) => {
82                write!(f, "{}*", r)?;
83                if !greedy {
84                    write!(f, "?")?;
85                }
86
87                Ok(())
88            }
89            Regex::ZeroOrOne(r, greedy) => {
90                write!(f, "{}?", r)?;
91                if !greedy {
92                    write!(f, "?")?;
93                }
94
95                Ok(())
96            }
97            Regex::Repeat1(r, greedy) => {
98                write!(f, "{}+", r)?;
99                if !greedy {
100                    write!(f, "?")?;
101                }
102                Ok(())
103            }
104            Regex::RepeatN(r, n) => write!(f, "{}{{{}}}", r, n),
105            Regex::RepeatMinMax(r, n, m, greedy) => {
106                if let Some(m) = m {
107                    write!(f, "{}{{{},{}}}", r, n, m)?;
108                } else {
109                    write!(f, "{}{{{},}}", r, n)?;
110                }
111                if !greedy {
112                    write!(f, "?")?;
113                }
114
115                Ok(())
116            }
117        }
118    }
119}
120
121impl<T: 'static> Regex<T> {
122    /// Like a `^` in regex. Build regex that matches the begging of the input.
123    pub fn begin() -> Self {
124        Regex::Begin
125    }
126    /// Like a `$` in regex. Build regex that matches the end of the input.
127    pub fn end() -> Self {
128        Regex::End
129    }
130    /// Like a `[character class]` in regex. Build regex that matches any value that satisfies the given predicate.
131    pub fn satisfy(f: impl Fn(&T) -> bool + 'static) -> Self {
132        Regex::Satisfy(Rc::new(f))
133    }
134
135    /// Like a `[^character class]` in regex. Build regex that matches any value that not satisfies the given predicate.
136    pub fn not_satisfy(f: impl Fn(&T) -> bool + 'static) -> Self {
137        Regex::NotSatisfy(Rc::new(move |x| !f(x)))
138    }
139
140    /// Like a `.` in regex. Build regex that matches any value.
141    pub fn any() -> Self {
142        Regex::Satisfy(Rc::new(|_| true))
143    }
144
145    /// Like a `?`, `??` in regex. Build regex that matches underlying regex zero or one times.
146    pub fn zero_or_one(reg: Self, greedy: bool) -> Self {
147        Regex::ZeroOrOne(reg.into(), greedy)
148    }
149
150    /// Like a `+`, `+?` in regex. Build regex that matches underlying regex one or more.
151    pub fn repeat1(reg: Self, greedy: bool) -> Self {
152        Regex::Repeat1(reg.into(), greedy)
153    }
154
155    /// Like a `*`, `*?` in regex. Build regex that matches underlying regex zero or more.
156    pub fn repeat0(reg: Self, greedy: bool) -> Self {
157        Regex::Repeat0(reg.into(), greedy)
158    }
159
160    /// Like a `{n}` in regex. Build regex that matches underlying regex N-times.
161    pub fn repeat_n(reg: Self, n: usize) -> Self {
162        Regex::RepeatN(reg.into(), n)
163    }
164
165    /// Like a `{n,}`, `{n,}?` in regex. Build regex that matches underlying regex N-times or more.
166    pub fn repeat_n_or_more(reg: Self, n: usize, greedy: bool) -> Self {
167        Regex::RepeatMinMax(reg.into(), n, None, greedy)
168    }
169
170    /// Like a `{n,m}`, `{n,m}?` in regex. Build regex that matches underlying regex n or n + 1 or ... or m times.
171    pub fn repeat_min_max(reg: Self, n: usize, m: usize, greedy: bool) -> Self {
172        Regex::RepeatMinMax(reg.into(), n, Some(m), greedy)
173    }
174
175    /// Like a `RS` in regex. Build regex that R followd by S.
176    pub fn concat(r: Self, s: Self) -> Self {
177        Regex::Concat(r.into(), s.into())
178    }
179
180    /// Like a `R|S` in regex. Build regex that matches R or S.
181    pub fn or(r: Self, s: Self) -> Self {
182        Regex::Or(r.into(), s.into())
183    }
184
185    /// Like a `(R)` in regex. Numbered capturing group (submatch).
186    pub fn group(r: Self) -> Self {
187        Regex::Group(r.into())
188    }
189
190    /// Like a `(?:R)` in regex. Numbered capturing group (submatch).
191    pub fn non_capturing_group(r: Self) -> Self {
192        Regex::NonCapturingGroup(r.into())
193    }
194
195    /// Like a `(?P<name>R)` in regex. Numbered capturing group (submatch).
196    pub fn named_group(name: &str, r: Self) -> Self {
197        Regex::NamedGroup(name.to_owned(), r.into())
198    }
199
200    /// Build regex that matches given value.
201    pub fn is(value: T) -> Self
202    where
203        T: PartialEq + 'static,
204    {
205        Regex::Satisfy(Rc::new(move |v| *v == value))
206    }
207
208    /// Build regex that matches given value sequence.
209    pub fn seq(values: &[T]) -> Self
210    where
211        T: PartialEq + Clone + 'static,
212    {
213        if values.len() == 1 {
214            Regex::is(values[0].clone())
215        } else {
216            let mut reg = Regex::is(values[0].clone());
217            for v in values.iter().skip(1) {
218                reg = Regex::concat(reg, Regex::is(v.clone()));
219            }
220            reg
221        }
222    }
223
224    pub fn compile(self) -> impl CompiledRegex<T> {
225        CompiledRegexInVm::compile(self)
226    }
227}