lazy_regex/lib.rs
1/*!
2
3With lazy-regex macros, regular expressions
4
5* are checked at compile time, with clear error messages
6* are wrapped in `once_cell` lazy static initializers so that they're compiled only once
7* can hold flags as suffix: `let case_insensitive_regex = regex!("ab*"i);`
8* are defined in a less verbose way
9
10The [regex!] macro returns references to normal instances of [regex::Regex] or [regex::bytes::Regex] so all the usual features are available.
11
12But most often, you won't even use the `regex!` macro but the other macros which are specialized for testing a match, replacing, or capturing groups in some common situations:
13
14* [Test a match](#test-a-match) with [regex_is_match!]
15* [Extract a value](#extract-a-value) with [regex_find!]
16* [Capture](#capture) with [regex_captures!] and [regex_captures_iter!]
17* [Replace with captured groups](#replace-with-captured-groups) with [regex_replace!] and [regex_replace_all!]
18* [Switch over patterns](#switch-over-patterns) with [regex_switch!]
19
20They support the `B` flag for the `regex::bytes::Regex` variant.
21
22All macros exist with a `bytes_` prefix for building `bytes::Regex`, so you also have [bytes_regex!], [bytes_regex_is_match!], [bytes_regex_find!], [bytes_regex_captures!], [bytes_regex_replace!], [bytes_regex_replace_all!], and [bytes_regex_switch!].
23
24Some structs of the regex crate are reexported to ease dependency managment.
25
26# Build Regexes
27
28```rust
29use lazy_regex::regex;
30
31// build a simple regex
32let r = regex!("sa+$");
33assert_eq!(r.is_match("Saa"), false);
34
35// build a regex with flag(s)
36let r = regex!("sa+$"i);
37assert_eq!(r.is_match("Saa"), true);
38
39// you can use a raw literal
40let r = regex!(r#"^"+$"#);
41assert_eq!(r.is_match("\"\""), true);
42
43// or a raw literal with flag(s)
44let r = regex!(r#"^\s*("[a-t]*"\s*)+$"#i);
45assert_eq!(r.is_match(r#" "Aristote" "Platon" "#), true);
46
47// build a regex that operates on &[u8]
48let r = regex!("(byte)?string$"B);
49assert_eq!(r.is_match(b"bytestring"), true);
50
51// there's no problem using the multiline definition syntax
52let r = regex!(r"(?x)
53 (?P<name>\w+)
54 -
55 (?P<version>[0-9.]+)
56");
57assert_eq!(r.find("This is lazy_regex-2.2!").unwrap().as_str(), "lazy_regex-2.2");
58// (look at the regex_captures! macro to easily extract the groups)
59
60```
61```compile_fail
62// this line doesn't compile because the regex is invalid:
63let r = regex!("(unclosed");
64
65```
66Supported regex flags: [`i`, `m`, `s`, `x`, `U`][regex::RegexBuilder], and you may also use `B` to build a bytes regex.
67
68The following regexes are equivalent:
69* `bytes_regex!("^ab+$"i)`
70* `bytes_regex!("(?i)^ab+$")`
71* `regex!("^ab+$"iB)`
72* `regex!("(?i)^ab+$"B)`
73
74They're all case insensitive instances of `regex::bytes::Regex`.
75
76
77# Test a match
78
79```rust
80use lazy_regex::*;
81
82let b = regex_is_match!("[ab]+", "car");
83assert_eq!(b, true);
84let b = bytes_regex_is_match!("[ab]+", b"car");
85assert_eq!(b, true);
86```
87
88doc: [regex_is_match!]
89
90
91# Extract a value
92
93```rust
94use lazy_regex::regex_find;
95
96let f_word = regex_find!(r"\bf\w+\b", "The fox jumps.");
97assert_eq!(f_word, Some("fox"));
98let f_word = regex_find!(r"\bf\w+\b"B, b"The forest is silent.");
99assert_eq!(f_word, Some(b"forest" as &[u8]));
100```
101
102doc: [regex_find!]
103
104# Capture
105
106```rust
107use lazy_regex::regex_captures;
108
109let (_, letter) = regex_captures!("([a-z])[0-9]+"i, "form A42").unwrap();
110assert_eq!(letter, "A");
111
112let (whole, name, version) = regex_captures!(
113 r"(\w+)-([0-9.]+)", // a literal regex
114 "This is lazy_regex-2.0!", // any expression
115).unwrap();
116assert_eq!(whole, "lazy_regex-2.0");
117assert_eq!(name, "lazy_regex");
118assert_eq!(version, "2.0");
119```
120
121There's no limit to the size of the tuple.
122It's checked at compile time to ensure you have the right number of capturing groups.
123
124You receive `""` for optional groups with no value.
125
126See [regex_captures!] and [regex_captures_iter!]
127
128# Replace with captured groups
129
130The [regex_replace!] and [regex_replace_all!] macros bring once compilation and compilation time checks to the `replace` and `replace_all` functions.
131
132## Replace with a closure
133
134```rust
135use lazy_regex::regex_replace_all;
136
137let text = "Foo8 fuu3";
138let text = regex_replace_all!(
139 r"\bf(\w+)(\d)"i,
140 text,
141 |_, name, digit| format!("F<{}>{}", name, digit),
142);
143assert_eq!(text, "F<oo>8 F<uu>3");
144```
145The number of arguments given to the closure is checked at compilation time to match the number of groups in the regular expression.
146
147If it doesn't match you get a clear error message at compilation time.
148
149## Replace with another kind of Replacer
150
151```rust
152use lazy_regex::regex_replace_all;
153let text = "UwU";
154let output = regex_replace_all!("U", text, "O");
155assert_eq!(&output, "OwO");
156```
157
158# Switch over patterns
159
160Execute the expression bound to the first matching regex, with named captured groups declared as varibles:
161
162```rust
163use lazy_regex::regex_switch;
164#[derive(Debug, PartialEq)]
165pub enum ScrollCommand {
166 Top,
167 Bottom,
168 Lines(i32),
169 Pages(i32),
170 JumpTo(String),
171}
172impl std::str::FromStr for ScrollCommand {
173 type Err = &'static str;
174 fn from_str(s: &str) -> Result<Self, Self::Err> {
175 regex_switch!(s,
176 "^scroll-to-top$" => Self::Top,
177 "^scroll-to-bottom$" => Self::Bottom,
178 r"^scroll-lines?\((?<n>[+-]?\d{1,4})\)$" => Self::Lines(n.parse().unwrap()),
179 r"^scroll-pages?\((?<n>[+-]?\d{1,4})\)$" => Self::Pages(n.parse().unwrap()),
180 r"^jump-to\((?<name>\w+)\)$" => Self::JumpTo(name.to_string()),
181 ).ok_or("unknown command")
182 }
183}
184assert_eq!("scroll-lines(42)".parse(), Ok(ScrollCommand::Lines(42)));
185assert_eq!("scroll-lines(XLII)".parse::<ScrollCommand>(), Err("unknown command"));
186```
187
188doc: [regex_switch!]
189
190# Shared lazy static
191
192When a regular expression is used in several functions, you sometimes don't want
193to repeat it but have a shared static instance.
194
195The [regex!] macro, while being backed by a lazy static regex, returns a reference.
196
197If you want to have a shared lazy static regex, use the [lazy_regex!] macro:
198
199```rust
200use lazy_regex::*;
201
202pub static GLOBAL_REX: Lazy<Regex> = lazy_regex!("^ab+$"i);
203```
204
205Like for the other macros, the regex is static, checked at compile time, and lazily built at first use.
206
207doc: [lazy_regex!]
208
209*/
210
211pub use {
212 lazy_regex_proc_macros::{
213 lazy_regex,
214 regex,
215 regex_captures,
216 regex_captures_iter,
217 regex_find,
218 regex_if,
219 regex_is_match,
220 regex_replace,
221 regex_replace_all,
222 regex_switch,
223 bytes_lazy_regex,
224 bytes_regex,
225 bytes_regex_captures,
226 bytes_regex_find,
227 bytes_regex_if,
228 bytes_regex_is_match,
229 bytes_regex_replace,
230 bytes_regex_replace_all,
231 bytes_regex_switch,
232 },
233 once_cell::sync::Lazy,
234};
235
236#[cfg(not(feature = "lite"))]
237pub use {
238 regex::{
239 self,
240 Captures, Regex, RegexBuilder,
241 bytes::{
242 Regex as BytesRegex,
243 RegexBuilder as BytesRegexBuilder
244 },
245 },
246};
247
248#[cfg(feature = "lite")]
249pub use {
250 regex_lite::{
251 self as regex,
252 Captures, Regex, RegexBuilder,
253 },
254};
255
256