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}