magic_regexp/
lib.rs

1/*!
2This crate provides a library for creating regular expressions in a more readable way.
3It stands on the shoulders of the [regex](https://crates.io/crates/regex) crate.
4
5For more specific details on the API for regular expressions, please see around the enums in the left sidebar.
6
7# Example: Find a date
8
9```rust
10use magic_regexp::{Digit, Times, create_reg_exp, Exactly, Condition, Text};
11use regex::Regex;
12
13const TO_SEARCH: &'static str = "On 2010-03-14, foo happened. On 2014-10-14, bar happened.";
14let input = Times(Digit, 4).and(Exactly(Text("-"))).and(Times(Digit, 2)).and(Exactly(Text(("-")))).and(Times(Digit, 2));
15assert_eq!(input.to_string(), r"\d{4}-\d{2}-\d{2}");
16
17let input = Times(Digit, 4).grouped_as("year").and(Exactly(Text("-"))).and(Times(Digit, 2).grouped_as("month")).and(Exactly(Text(("-")))).and(Times(Digit, 2).grouped_as("day"));
18let re = create_reg_exp(input).unwrap();
19assert!(re.is_match("2014-01-01"));
20assert_eq!(re.find_iter(TO_SEARCH).count(), 2);
21
22for caps in re.captures_iter(TO_SEARCH) {
23    // Note that all of the unwraps are actually OK for this regex
24    // because the only way for the regex to match is if all of the
25    // capture groups match. This is not true in general though!
26    println!("year: {}, month: {}, day: {}",
27    caps.get(1).unwrap().as_str(),
28    caps.get(2).unwrap().as_str(),
29    caps.get(3).unwrap().as_str());
30}
31```
32*/
33
34mod core;
35pub use crate::core::*;
36
37use regex::Regex;
38
39/// Returns the regex, which represents the given statement.
40/// This is only for convenience and compatibility with magic-regex from npm.
41///
42/// # Example
43/// ```
44/// use magic_regexp::{Digit, Times, create_reg_exp, Exactly, Condition, Text};
45/// use regex::Regex;
46///
47/// const TO_SEARCH: &'static str = "On 2010-03-14, foo happened. On 2014-10-14, bar happened.";
48/// let input = Times(Digit, 4).and(Exactly(Text("-"))).and(Times(Digit, 2)).and(Exactly(Text(("-")))).and(Times(Digit, 2));
49/// assert_eq!(input.to_string(), r"\d{4}-\d{2}-\d{2}");
50/// let input = Times(Digit, 4).grouped_as("year").and(Exactly(Text("-"))).and(Times(Digit, 2).grouped_as("month")).and(Exactly(Text(("-")))).and(Times(Digit, 2).grouped_as("day"));
51/// let re = create_reg_exp(input).unwrap();
52/// assert!(re.is_match("2014-01-01"));
53/// assert_eq!(re.find_iter(TO_SEARCH).count(), 2);
54/// for caps in re.captures_iter(TO_SEARCH) {
55///     // Note that all of the unwraps are actually OK for this regex
56///     // because the only way for the regex to match is if all of the
57///     // capture groups match. This is not true in general though!
58/// println!("year: {}, month: {}, day: {}",
59///         caps.get(1).unwrap().as_str(),
60///         caps.get(2).unwrap().as_str(),
61///         caps.get(3).unwrap().as_str());
62/// }
63/// ```
64pub fn create_reg_exp(input: impl AsRegex) -> Result<Regex> {
65    input.as_regex()
66}
67
68#[cfg(test)]
69mod tests {
70    use super::{create_reg_exp, not, Exactly, OneOrMore, Type::Digit};
71    use crate::Input::Maybe;
72    use crate::Type::Text;
73
74    #[test]
75    fn test_single_digit() {
76        let input = Exactly(Digit);
77        let regex = create_reg_exp(input).unwrap();
78        assert!(regex.is_match("1"));
79        assert!(!regex.is_match("12"));
80        assert!(regex.is_match("1 2"));
81    }
82
83    #[test]
84    fn test_maybe_digit() {
85        let input = Maybe(Digit);
86        let regex = create_reg_exp(input).unwrap();
87        assert!(regex.is_match("1"));
88        assert!(regex.is_match(""));
89        assert!(regex.is_match("12"));
90        assert!(regex.is_match("1 2"));
91    }
92    #[test]
93    fn test_one_or_more_digits() {
94        let input = OneOrMore(Digit);
95        let regex = create_reg_exp(input).unwrap();
96        assert!(regex.is_match("1"));
97        assert!(regex.is_match("12"));
98        assert!(regex.is_match("1 2"));
99        assert!(regex.is_match("123"));
100        assert!(regex.is_match("12a3"));
101    }
102
103    #[test]
104    fn test_not_digit() {
105        let input = Exactly(not(Digit));
106        let regex = create_reg_exp(input).unwrap();
107        assert!(!regex.is_match("1"));
108        assert!(regex.is_match("a"));
109    }
110
111    #[test]
112    fn test_not_not_stuff() {
113        let input = Exactly(not(not(Digit)));
114        let regex = create_reg_exp(input).unwrap();
115        assert!(regex.is_match("1"));
116        assert!(!regex.is_match("a"));
117    }
118
119    #[test]
120    fn test_exactly_text() {
121        let input = Exactly(Text("welt".into()));
122        let regex = create_reg_exp(input).unwrap();
123        assert!(regex.is_match("Hallo welt"));
124        assert!(!regex.is_match("Hallo Welt"));
125    }
126}