|
7 | 7 | //! The goal of this crate is simple: give everybody the power of regular expressions without having |
8 | 8 | //! to learn the complicated syntax. It is inspired by [ReadableRegex.jl](https://github.com/jkrumbiegel/ReadableRegex.jl). |
9 | 9 |
|
10 | | -//!# Example usage |
11 | | -//!## Matching a date |
12 | | -//!If you want to match a date of the format `2021-10-30`, you would use the following code to generate a regex: |
13 | | -//!```rust |
14 | | -//!let hr = human_regex::HumanRegex::new() |
15 | | -//! .begin() |
16 | | -//! .exactly(4, human_regex::DIGIT) |
17 | | -//! .text("-") |
18 | | -//! .exactly(2, human_regex::DIGIT) |
19 | | -//! .text("-") |
20 | | -//! .exactly(2, human_regex::DIGIT) |
21 | | -//! .end(); |
22 | | -//!assert!(hr.is_match("2014-01-01")); |
23 | | -//!``` |
24 | | -//!Specifically, this chunk of code would yield the regex `^\d{4}-\d{2}-\d{2}$`, which is exactly what we want! |
| 10 | +//! # Example usage |
| 11 | +//! ## Matching a date |
| 12 | +//! If you want to match a date of the format `2021-10-30`, you could use the following code to generate a regex: |
| 13 | +//! ```rust |
| 14 | +//! use human_regex as hr; |
| 15 | +//! let regex_string = hr::begin() |
| 16 | +//! + hr::exactly(4, hr::digit()) |
| 17 | +//! + hr::text("-") |
| 18 | +//! + hr::exactly(2, hr::digit()) |
| 19 | +//! + hr::text("-") |
| 20 | +//! + hr::exactly(2, hr::digit()) |
| 21 | +//! + hr::end(); |
| 22 | +//! assert!(regex_string.to_regex().is_match("2014-01-01")) |
| 23 | +//! ``` |
25 | 24 |
|
26 | 25 | use regex::Regex; |
27 | 26 | use std::fmt; |
| 27 | +use std::ops::Add; |
28 | 28 |
|
29 | | -/// A constant for matching any character (except for \n) |
30 | | -pub const ANY: &str = r"."; |
31 | | -/// A constant for the digit character class (i.e., the digits 0 through 9) |
32 | | -pub const DIGIT: &str = r"\d"; |
33 | | -/// A constant for the non-digit character class (i.e., everything BUT the digits 0-9) |
34 | | -pub const NON_DIGIT: &str = r"\D"; |
35 | | -/// A constant for the word character class (i.e., all alphanumeric characters plus underscore) |
36 | | -pub const WORD: &str = r"\w"; |
37 | | -/// A constant for the non-word character class (i.e., everything BUT the alphanumeric characters plus underscore) |
38 | | -pub const NON_WORD: &str = r"\W"; |
| 29 | +/// A function for matching any character (except for \n) |
| 30 | +pub fn any() -> HumanRegex { |
| 31 | + HumanRegex(r".".to_string()) |
| 32 | +} |
| 33 | +/// A function for the digit character class (i.e., the digits 0 through 9) |
| 34 | +pub fn digit() -> HumanRegex { |
| 35 | + HumanRegex(r"\d".to_string()) |
| 36 | +} |
| 37 | +/// A function for the non-digit character class (i.e., everything BUT the digits 0-9) |
| 38 | +pub fn non_digit() -> HumanRegex { |
| 39 | + HumanRegex(r"\D".to_string()) |
| 40 | +} |
| 41 | +/// A function for the word character class (i.e., all alphanumeric characters plus underscore) |
| 42 | +pub fn word() -> HumanRegex { |
| 43 | + HumanRegex(r"\w".to_string()) |
| 44 | +} |
| 45 | +/// A function for the non-word character class (i.e., everything BUT the alphanumeric characters plus underscore) |
| 46 | +pub fn non_word() -> HumanRegex { |
| 47 | + HumanRegex(r"\W".to_string()) |
| 48 | +} |
39 | 49 | /// A constant for the whitespace character class (i.e., space and tab) |
40 | | -pub const WHITESPACE: &str = r"\t"; |
41 | | -/// A constant for the whitespace character class (i.e., everything BUT space and tab) |
42 | | -pub const NON_WHITESPACE: &str = r"\T"; |
43 | | - |
44 | | -/// The HumanRegex struct which maintains and updates the regex string |
45 | | -#[derive(Default, Debug)] |
46 | | -pub struct HumanRegex { |
47 | | - /// The internally-maintained true regex string |
48 | | - pub regex_string: String, |
| 50 | +pub fn whitespace() -> HumanRegex { |
| 51 | + HumanRegex(r"\t".to_string()) |
| 52 | +} |
| 53 | +/// A function for the whitespace character class (i.e., everything BUT space and tab) |
| 54 | +pub fn non_whitespace() -> HumanRegex { |
| 55 | + HumanRegex(r"\T".to_string()) |
49 | 56 | } |
50 | 57 |
|
51 | | -impl HumanRegex { |
52 | | - /// Generate a new HumanRegex with a blank regex_string |
53 | | - pub fn new() -> Self { |
54 | | - HumanRegex { |
55 | | - regex_string: String::from(""), |
56 | | - } |
57 | | - } |
| 58 | +/// A function to match the beginning of a string |
| 59 | +pub fn begin() -> HumanRegex { |
| 60 | + HumanRegex(r"^".to_string()) |
| 61 | +} |
58 | 62 |
|
59 | | - /// Match exactly _n_ of a certain target |
60 | | - pub fn exactly<T>(&self, n: u8, target: T) -> Self |
61 | | - where |
62 | | - T: Into<String> + fmt::Display, |
63 | | - { |
64 | | - let new_regex = format!("{}{}{{{}}}", self.regex_string, target, n); |
65 | | - HumanRegex { |
66 | | - regex_string: new_regex, |
67 | | - } |
68 | | - } |
| 63 | +/// A function to match the end of a string |
| 64 | +pub fn end() -> HumanRegex { |
| 65 | + HumanRegex(r"$".to_string()) |
| 66 | +} |
69 | 67 |
|
70 | | - /// Match at least _n_ of a certain target |
71 | | - pub fn at_least(&self, n: u8, target: &str) -> Self { |
72 | | - let new_regex = format!("{}{}{{{},}}", self.regex_string, target, n); |
73 | | - HumanRegex { |
74 | | - regex_string: new_regex, |
75 | | - } |
76 | | - } |
| 68 | +/// The HumanRegex struct which maintains and updates the regex string |
| 69 | +#[derive(Debug)] |
| 70 | +pub struct HumanRegex(String); |
77 | 71 |
|
78 | | - /// Match at least _n_ and at most _m_ of a certain target |
79 | | - pub fn at_least_at_most(&self, n: u8, m: u8, target: &str) -> Self { |
80 | | - let new_regex = format!("{}{}{{{},{}}}", self.regex_string, target, n, m); |
81 | | - HumanRegex { |
82 | | - regex_string: new_regex, |
83 | | - } |
| 72 | +impl HumanRegex { |
| 73 | + /// Convert to a rust Regex |
| 74 | + pub fn to_regex(&self) -> Regex { |
| 75 | + Regex::new(&*self.0).unwrap() |
84 | 76 | } |
| 77 | +} |
85 | 78 |
|
86 | | - /// Match one or more of a certain target |
87 | | - pub fn one_or_more(&self, target: &str) -> Self { |
88 | | - let new_regex = format!("{}{}+", self.regex_string, target); |
89 | | - HumanRegex { |
90 | | - regex_string: new_regex, |
91 | | - } |
92 | | - } |
| 79 | +/// Match at least _n_ of a certain target |
| 80 | +pub fn at_least<T>(n: u8, target: T) -> HumanRegex |
| 81 | +where |
| 82 | + T: Into<String> + fmt::Display, |
| 83 | +{ |
| 84 | + HumanRegex(format!("{}{{{}}}", target, n)) |
| 85 | +} |
93 | 86 |
|
94 | | - /// Match zero or more of a certain target |
95 | | - pub fn zero_or_more(&self, target: &str) -> Self { |
96 | | - let new_regex = format!("{}{}*", self.regex_string, target); |
97 | | - HumanRegex { |
98 | | - regex_string: new_regex, |
99 | | - } |
100 | | - } |
| 87 | +/// Match at least _n_ and at most _m_ of a certain target |
| 88 | +pub fn at_least_at_most<T>(n: u8, m: u8, target: T) -> HumanRegex |
| 89 | +where |
| 90 | + T: Into<String> + fmt::Display, |
| 91 | +{ |
| 92 | + HumanRegex(format!("{}{{{},{}}}", target, n, m)) |
| 93 | +} |
101 | 94 |
|
102 | | - /// Match zero or one of a certain target |
103 | | - pub fn zero_or_one(&self, target: &str) -> Self { |
104 | | - let new_regex = format!("{}{}?", self.regex_string, target); |
105 | | - HumanRegex { |
106 | | - regex_string: new_regex, |
107 | | - } |
108 | | - } |
| 95 | +/// Match one or more of a certain target |
| 96 | +pub fn one_or_more<T>(target: T) -> HumanRegex |
| 97 | +where |
| 98 | + T: Into<String> + fmt::Display, |
| 99 | +{ |
| 100 | + HumanRegex(format!("{}+", target)) |
| 101 | +} |
109 | 102 |
|
110 | | - /// Add text directly to the match string |
111 | | - pub fn text<T>(&self, text: T) -> Self |
112 | | - where |
113 | | - T: Into<String> + fmt::Display, |
114 | | - { |
115 | | - let new_regex = format!("{}{}", self.regex_string, text); |
116 | | - HumanRegex { |
117 | | - regex_string: new_regex, |
118 | | - } |
119 | | - } |
| 103 | +/// Match zero or more of a certain target |
| 104 | +pub fn zero_or_more<T>(target: T) -> HumanRegex |
| 105 | +where |
| 106 | + T: Into<String> + fmt::Display, |
| 107 | +{ |
| 108 | + HumanRegex(format!("{}*", target)) |
| 109 | +} |
120 | 110 |
|
121 | | - /// Represents the beginning of the text |
122 | | - pub fn begin(&self) -> Self { |
123 | | - let new_regex = format!("{}{}", self.regex_string, r"^"); |
124 | | - HumanRegex { |
125 | | - regex_string: new_regex, |
126 | | - } |
127 | | - } |
| 111 | +/// Match zero or one of a certain target |
| 112 | +pub fn zero_or_one<T>(target: T) -> HumanRegex |
| 113 | +where |
| 114 | + T: Into<String> + fmt::Display, |
| 115 | +{ |
| 116 | + HumanRegex(format!("{}?", target)) |
| 117 | +} |
128 | 118 |
|
129 | | - /// Represents the end of the text |
130 | | - pub fn end(&self) -> Self { |
131 | | - let new_regex = format!("{}{}", self.regex_string, r"$"); |
132 | | - HumanRegex { |
133 | | - regex_string: new_regex, |
134 | | - } |
135 | | - } |
| 119 | +/// Match exactly _n_ of a certain target |
| 120 | +pub fn exactly<T>(n: u8, target: T) -> HumanRegex |
| 121 | +where |
| 122 | + T: Into<String> + fmt::Display, |
| 123 | +{ |
| 124 | + HumanRegex(format!("{}{{{}}}", target, n)) |
| 125 | +} |
136 | 126 |
|
137 | | - /// Generates a new human regex directly from a regex string |
138 | | - pub fn from_regex_string(regex_string: &str) -> Self { |
139 | | - HumanRegex { |
140 | | - regex_string: String::from(regex_string), |
141 | | - } |
142 | | - } |
| 127 | +/// Add generic text to the regex string |
| 128 | +pub fn text<T>(text: T) -> HumanRegex |
| 129 | +where |
| 130 | + T: Into<String> + fmt::Display, |
| 131 | +{ |
| 132 | + HumanRegex(text.to_string()) |
| 133 | +} |
143 | 134 |
|
144 | | - /// Returns the current state of the constructed regex string as a Regex object |
145 | | - pub fn get_regex(&self) -> Regex { |
146 | | - Regex::new(&*self.regex_string).unwrap() |
147 | | - } |
| 135 | +impl Add for HumanRegex { |
| 136 | + type Output = Self; |
148 | 137 |
|
149 | | - /// Checks whether or not a string matches with the constructed regex |
150 | | - pub fn is_match(&self, string_to_match: &str) -> bool { |
151 | | - let re = Regex::new(&*self.regex_string).unwrap(); |
152 | | - re.is_match(string_to_match) |
| 138 | + fn add(self, rhs: Self) -> Self::Output { |
| 139 | + let owned_string = format!("{}{}", self.to_string(), rhs.to_string()); |
| 140 | + HumanRegex(owned_string) |
153 | 141 | } |
154 | 142 | } |
155 | 143 |
|
156 | 144 | impl fmt::Display for HumanRegex { |
157 | 145 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
158 | | - write!(f, "{}", self.regex_string) |
| 146 | + write!(f, "{}", self.0) |
159 | 147 | } |
160 | 148 | } |
161 | 149 |
|
|
0 commit comments