readable_regex/
lib.rs

1//! ## Regex for human beings.
2//!
3//! Regex is useful. But, sincerely, since code it is more read than written regex could
4//! be more understandable in a verbose mode.
5//!
6//! `readable-regex` crate is a set of tools to build those regexes in a verbose way. Which aims
7//! to improve readability of code.
8//!
9//! ### Available APIs
10//!
11//! The main wrapper is the [`ReadableRe`] enum.
12//!
13//! There are tow main options to build regexes with it, either using the **enum** itself:
14//!
15//! ```
16//! use readable_regex::ReadableRe;
17//! let query = ReadableRe::Raw("<some regex expression>");
18//! ```
19//!
20//! or by using the functions wrappers around it:
21//!
22//! ```
23//! use readable_regex::raw_regex;
24//! let query = raw_regex("<some regex expression>");
25//! ```
26//!
27//! Also, any combination of them:
28//!
29//! ```
30//! use readable_regex::{digit, group};
31//! use readable_regex::ReadableRe::*;
32//! let query = group(digit() + Digit + digit());
33//! println!("{}", query.to_string());
34//! ```
35//!
36//! ### Examples
37//! How to build a simple date match (as implemented in the `datetime` module under `presets` feature):
38//! ```
39//! use once_cell::sync::Lazy;
40//! use readable_regex::*;
41//! use readable_regex::ReadableRe::*;
42//!
43//! /// Month day, `01`-`31`
44//! pub const DAY: Lazy<ReadableRe> = Lazy::new(|| {
45//!     either([
46//!         Raw("0") + chars("1-9"),
47//!         chars("12") + chars("1-9"),
48//!         Raw("3") + chars("01"),
49//!     ])
50//! });
51//!
52//! /// Month numeral, `01`-`12`
53//! pub const MONTH: Lazy<ReadableRe> =
54//!     Lazy::new(|| either([Raw("0") + chars("1-9"), Raw("1") + chars("0-2")]));
55//!
56//! /// Years from `1000` to `2999`
57//! pub const YEAR: Lazy<ReadableRe> = Lazy::new(|| chars("12") + exactly(3, Digit));
58//!
59//! /// Date Format `YYYY-MM-dd`
60//! pub const DATE_Y_M_D: Lazy<ReadableRe> = Lazy::new(|| {
61//!     group(
62//!         group(YEAR.clone())
63//!             + chars(r"-/.\\")
64//!             + group(MONTH.clone())
65//!             + chars(r"-/.\\")
66//!             + group(DAY.clone()),
67//!     )
68//! });
69//!
70//! assert!(DATE_Y_M_D.compile().unwrap().is_match("2022/04/18"));
71//! ```
72//!
73//! ### Features
74//! * `re` => Use [`regex`] crate backend.
75//! * `re-fancy` => Use [`fancy_regex`] crate backend and expands this crate functionality.
76
77mod constants;
78#[cfg(feature = "presets")]
79pub mod presets;
80pub mod readable;
81pub mod solvers;
82
83pub use readable::ReadableRe;
84use std::ops::RangeBounds;
85
86pub const fn digit<'a>() -> ReadableRe<'a> {
87    ReadableRe::Digit
88}
89
90pub const fn word<'a>() -> ReadableRe<'a> {
91    ReadableRe::Word
92}
93
94pub const fn whitespace<'a>() -> ReadableRe<'a> {
95    ReadableRe::Whitespace
96}
97
98pub const fn non_digit<'a>() -> ReadableRe<'a> {
99    ReadableRe::NonDigit
100}
101
102pub const fn non_word<'a>() -> ReadableRe<'a> {
103    ReadableRe::NonWord
104}
105
106pub const fn non_whitespace<'a>() -> ReadableRe<'a> {
107    ReadableRe::NonWhitespace
108}
109
110pub const fn boundary<'a>() -> ReadableRe<'a> {
111    ReadableRe::Boundary
112}
113
114pub const fn ascii_letter<'a>() -> ReadableRe<'a> {
115    ReadableRe::AsciiLetter
116}
117
118pub const fn ascii_non_letter<'a>() -> ReadableRe<'a> {
119    ReadableRe::AsciiNonLetter
120}
121
122pub const fn ascii_uppercase<'a>() -> ReadableRe<'a> {
123    ReadableRe::AsciiUppercase
124}
125
126pub const fn ascii_non_uppercase<'a>() -> ReadableRe<'a> {
127    ReadableRe::AsciiNonUppercase
128}
129
130pub const fn ascii_lowercase<'a>() -> ReadableRe<'a> {
131    ReadableRe::AsciiLowercase
132}
133
134pub const fn ascii_non_lowercase<'a>() -> ReadableRe<'a> {
135    ReadableRe::AsciiNonLowercase
136}
137
138pub const fn ascii_alphanumeric<'a>() -> ReadableRe<'a> {
139    ReadableRe::AsciiAlphanumeric
140}
141
142pub const fn ascii_non_alphanumeric<'a>() -> ReadableRe<'a> {
143    ReadableRe::AsciiNonAlphanumeric
144}
145
146pub const fn ascii_numeric<'a>() -> ReadableRe<'a> {
147    ReadableRe::AsciiNumeric
148}
149
150pub const fn ascii_non_numeric<'a>() -> ReadableRe<'a> {
151    ReadableRe::AsciiNonNumeric
152}
153
154pub const fn hexadecimal<'a>() -> ReadableRe<'a> {
155    ReadableRe::Hexadecimal
156}
157
158pub const fn non_hexadecimal<'a>() -> ReadableRe<'a> {
159    ReadableRe::NonHexadecimal
160}
161
162pub const fn anything<'a>() -> ReadableRe<'a> {
163    ReadableRe::Anything
164}
165
166pub const fn everything<'a>() -> ReadableRe<'a> {
167    ReadableRe::Everything
168}
169
170pub const fn something_greedy<'a>() -> ReadableRe<'a> {
171    ReadableRe::SomethingGreedy
172}
173
174pub const fn something<'a>() -> ReadableRe<'a> {
175    ReadableRe::Something
176}
177
178pub const fn any_char<'a>() -> ReadableRe<'a> {
179    ReadableRe::AnyChar
180}
181
182pub const fn period<'a>() -> ReadableRe<'a> {
183    ReadableRe::Period
184}
185
186pub const fn caret<'a>() -> ReadableRe<'a> {
187    ReadableRe::Caret
188}
189
190pub const fn dollar<'a>() -> ReadableRe<'a> {
191    ReadableRe::Dollar
192}
193
194pub const fn asterisk<'a>() -> ReadableRe<'a> {
195    ReadableRe::Asterisk
196}
197
198pub const fn plus_sign<'a>() -> ReadableRe<'a> {
199    ReadableRe::PlusSign
200}
201
202pub const fn minus_sign<'a>() -> ReadableRe<'a> {
203    ReadableRe::MinusSign
204}
205
206pub const fn question_mark<'a>() -> ReadableRe<'a> {
207    ReadableRe::QuestionMark
208}
209
210pub const fn open_brace<'a>() -> ReadableRe<'a> {
211    ReadableRe::OpenBrace
212}
213
214pub const fn close_brace<'a>() -> ReadableRe<'a> {
215    ReadableRe::CloseBrace
216}
217
218pub const fn open_bracket<'a>() -> ReadableRe<'a> {
219    ReadableRe::OpenBracket
220}
221
222pub const fn close_bracket<'a>() -> ReadableRe<'a> {
223    ReadableRe::CloseBracket
224}
225
226pub const fn open_parenthesis<'a>() -> ReadableRe<'a> {
227    ReadableRe::OpenParenthesis
228}
229
230pub const fn close_parenthesis<'a>() -> ReadableRe<'a> {
231    ReadableRe::CloseParenthesis
232}
233
234pub const fn back_slash<'a>() -> ReadableRe<'a> {
235    ReadableRe::BackSlash
236}
237
238pub const fn pipe<'a>() -> ReadableRe<'a> {
239    ReadableRe::Pipe
240}
241
242pub const fn new_line<'a>() -> ReadableRe<'a> {
243    ReadableRe::Newline
244}
245
246pub const fn tab<'a>() -> ReadableRe<'a> {
247    ReadableRe::Tab
248}
249
250pub const fn quote<'a>() -> ReadableRe<'a> {
251    ReadableRe::Quote
252}
253
254pub const fn double_quote<'a>() -> ReadableRe<'a> {
255    ReadableRe::DoubleQuote
256}
257
258#[cfg(feature = "re-fancy")]
259pub const fn back1<'a>() -> ReadableRe<'a> {
260    ReadableRe::Back1
261}
262
263#[cfg(feature = "re-fancy")]
264pub const fn back2<'a>() -> ReadableRe<'a> {
265    ReadableRe::Back2
266}
267
268#[cfg(feature = "re-fancy")]
269pub const fn back3<'a>() -> ReadableRe<'a> {
270    ReadableRe::Back3
271}
272
273#[cfg(feature = "re-fancy")]
274pub const fn back4<'a>() -> ReadableRe<'a> {
275    ReadableRe::Back4
276}
277
278#[cfg(feature = "re-fancy")]
279pub const fn back5<'a>() -> ReadableRe<'a> {
280    ReadableRe::Back5
281}
282
283#[cfg(feature = "re-fancy")]
284pub const fn back6<'a>() -> ReadableRe<'a> {
285    ReadableRe::Back6
286}
287
288#[cfg(feature = "re-fancy")]
289pub const fn back7<'a>() -> ReadableRe<'a> {
290    ReadableRe::Back7
291}
292
293#[cfg(feature = "re-fancy")]
294pub const fn back8<'a>() -> ReadableRe<'a> {
295    ReadableRe::Back8
296}
297
298#[cfg(feature = "re-fancy")]
299pub const fn back9<'a>() -> ReadableRe<'a> {
300    ReadableRe::Back9
301}
302
303pub const fn raw_regex(s: &str) -> ReadableRe {
304    ReadableRe::Raw(s)
305}
306
307pub const fn string_regex<'a>(s: String) -> ReadableRe<'a> {
308    ReadableRe::String(s)
309}
310
311pub fn concat<'a>(iter: impl IntoIterator<Item = ReadableRe<'a>>) -> ReadableRe<'a> {
312    ReadableRe::Concat(solvers::Concat::new(iter))
313}
314
315#[cfg(feature = "re-fancy")]
316pub const fn back_reference<'a>(n: usize) -> ReadableRe<'a> {
317    ReadableRe::BackReference(solvers::BackReference(n))
318}
319
320pub fn escape_str(s: &str) -> ReadableRe {
321    ReadableRe::Escape(solvers::Escape::new_str(s))
322}
323
324pub fn escape(re: ReadableRe) -> ReadableRe {
325    ReadableRe::Escape(solvers::Escape::new(re))
326}
327
328pub fn group(re: ReadableRe) -> ReadableRe {
329    ReadableRe::Group(solvers::Group::new(re))
330}
331
332#[cfg(feature = "re-fancy")]
333pub fn positive_look_ahead(re: ReadableRe) -> ReadableRe {
334    ReadableRe::PositiveLookAhead(solvers::PositiveLookAhead::new(re))
335}
336
337#[cfg(feature = "re-fancy")]
338pub fn negative_look_ahead(re: ReadableRe) -> ReadableRe {
339    ReadableRe::NegativeLookAhead(solvers::NegativeLookAhead::new(re))
340}
341
342#[cfg(feature = "re-fancy")]
343pub fn positive_look_behind(re: ReadableRe) -> ReadableRe {
344    ReadableRe::PositiveLookBehind(solvers::PositiveLookBehind::new(re))
345}
346
347#[cfg(feature = "re-fancy")]
348pub fn negative_look_behind(re: ReadableRe) -> ReadableRe {
349    ReadableRe::NegativeLookBehind(solvers::NegativeLookBehind::new(re))
350}
351
352pub fn named_group<'a>(name: &'a str, re: ReadableRe<'a>) -> ReadableRe<'a> {
353    ReadableRe::NamedGroup(solvers::NamedGroup::new(name, re))
354}
355
356pub fn non_capture_group(re: ReadableRe) -> ReadableRe {
357    ReadableRe::NonCaptureGroup(solvers::NonCaptureGroup::new(re))
358}
359
360pub fn optional(re: ReadableRe) -> ReadableRe {
361    ReadableRe::Optional(solvers::Optional::new(re))
362}
363
364pub fn either<'a>(iter: impl IntoIterator<Item = ReadableRe<'a>>) -> ReadableRe<'a> {
365    ReadableRe::Either(solvers::Either::new(iter))
366}
367
368pub fn exactly(n: usize, re: ReadableRe) -> ReadableRe {
369    ReadableRe::Exactly(solvers::Exactly::new(n, re))
370}
371
372pub fn ranged<R>(range: R, re: ReadableRe) -> ReadableRe
373where
374    R: RangeBounds<usize> + 'static,
375{
376    ReadableRe::Ranged(solvers::Ranged::new(range, re))
377}
378
379pub fn at_least(n: usize, re: ReadableRe) -> ReadableRe {
380    ReadableRe::Ranged(solvers::Ranged::new(n.., re))
381}
382
383pub fn at_most(n: usize, re: ReadableRe) -> ReadableRe {
384    ReadableRe::Ranged(solvers::Ranged::new(..n, re))
385}
386
387pub fn zero_or_more(re: ReadableRe) -> ReadableRe {
388    ReadableRe::ZeroOrMore(solvers::ZeroOrMore::new(re))
389}
390
391pub fn zero_or_more_lazy(re: ReadableRe) -> ReadableRe {
392    ReadableRe::ZeroOrMoreLazy(solvers::ZeroOrMoreLazy::new(re))
393}
394
395pub fn one_or_more(re: ReadableRe) -> ReadableRe {
396    ReadableRe::OneOrMore(solvers::OneOrMore::new(re))
397}
398
399pub fn one_or_more_lazy(re: ReadableRe) -> ReadableRe {
400    ReadableRe::OneOrMoreLazy(solvers::OneOrMoreLazy::new(re))
401}
402
403pub fn starts_with(re: ReadableRe) -> ReadableRe {
404    ReadableRe::StartsWith(solvers::StartsWith::new(re))
405}
406
407pub fn ends_with(re: ReadableRe) -> ReadableRe {
408    ReadableRe::EndsWith(solvers::EndsWith::new(re))
409}
410
411pub fn starts_and_ends_with(re: ReadableRe) -> ReadableRe {
412    ReadableRe::StartsAndEndsWith(solvers::StartsAndEndsWith::new(re))
413}
414
415pub fn chars(re: &str) -> ReadableRe {
416    ReadableRe::Chars(solvers::Chars::new(re))
417}
418
419pub fn not_chars<'a>(s: &str) -> ReadableRe<'a> {
420    ReadableRe::NotChars(solvers::NotChars::new(s))
421}
422
423#[cfg(feature = "re-fancy")]
424pub fn atomic_group(re: ReadableRe) -> ReadableRe {
425    ReadableRe::AtomicGroup(solvers::AtomicGroup::new(re))
426}