-
Notifications
You must be signed in to change notification settings - Fork 461
/
Copy pathbuilders.rs
2539 lines (2452 loc) · 105 KB
/
builders.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#![allow(warnings)]
// This module defines an internal builder that encapsulates all interaction
// with meta::Regex construction, and then 4 public API builders that wrap
// around it. The docs are essentially repeated on each of the 4 public
// builders, with tweaks to the examples as needed.
//
// The reason why there are so many builders is partially because of a misstep
// in the initial API design: the builder constructor takes in the pattern
// strings instead of using the `build` method to accept the pattern strings.
// This means `new` has a different signature for each builder. It probably
// would have been nicer to to use one builder with `fn new()`, and then add
// `build(pat)` and `build_many(pats)` constructors.
//
// The other reason is because I think the `bytes` module should probably
// have its own builder type. That way, it is completely isolated from the
// top-level API.
//
// If I could do it again, I'd probably have a `regex::Builder` and a
// `regex::bytes::Builder`. Each would have `build` and `build_set` (or
// `build_many`) methods for constructing a single pattern `Regex` and a
// multi-pattern `RegexSet`, respectively.
use alloc::{
string::{String, ToString},
sync::Arc,
vec,
vec::Vec,
};
use regex_automata::{
meta, nfa::thompson::WhichCaptures, util::syntax, MatchKind,
};
use crate::error::Error;
/// A builder for constructing a `Regex`, `bytes::Regex`, `RegexSet` or a
/// `bytes::RegexSet`.
///
/// This is essentially the implementation of the four different builder types
/// in the public API: `RegexBuilder`, `bytes::RegexBuilder`, `RegexSetBuilder`
/// and `bytes::RegexSetBuilder`.
#[derive(Clone, Debug)]
struct Builder {
pats: Vec<String>,
metac: meta::Config,
syntaxc: syntax::Config,
}
impl Default for Builder {
fn default() -> Builder {
let metac = meta::Config::new()
.nfa_size_limit(Some(10 * (1 << 20)))
.hybrid_cache_capacity(2 * (1 << 20));
Builder { pats: vec![], metac, syntaxc: syntax::Config::default() }
}
}
impl Builder {
fn new<I, S>(patterns: I) -> Builder
where
S: AsRef<str>,
I: IntoIterator<Item = S>,
{
let mut b = Builder::default();
b.pats.extend(patterns.into_iter().map(|p| p.as_ref().to_string()));
b
}
fn build_one_string(&self) -> Result<crate::Regex, Error> {
assert_eq!(1, self.pats.len());
let metac = self
.metac
.clone()
.match_kind(MatchKind::LeftmostFirst)
.utf8_empty(true);
let syntaxc = self.syntaxc.clone().utf8(true);
let pattern = Arc::from(self.pats[0].as_str());
meta::Builder::new()
.configure(metac)
.syntax(syntaxc)
.build(&pattern)
.map(|meta| crate::Regex { meta, pattern })
.map_err(Error::from_meta_build_error)
}
fn build_one_bytes(&self) -> Result<crate::bytes::Regex, Error> {
assert_eq!(1, self.pats.len());
let metac = self
.metac
.clone()
.match_kind(MatchKind::LeftmostFirst)
.utf8_empty(false);
let syntaxc = self.syntaxc.clone().utf8(false);
let pattern = Arc::from(self.pats[0].as_str());
meta::Builder::new()
.configure(metac)
.syntax(syntaxc)
.build(&pattern)
.map(|meta| crate::bytes::Regex { meta, pattern })
.map_err(Error::from_meta_build_error)
}
fn build_many_string(&self) -> Result<crate::RegexSet, Error> {
let metac = self
.metac
.clone()
.match_kind(MatchKind::All)
.utf8_empty(true)
.which_captures(WhichCaptures::None);
let syntaxc = self.syntaxc.clone().utf8(true);
let patterns = Arc::from(self.pats.as_slice());
meta::Builder::new()
.configure(metac)
.syntax(syntaxc)
.build_many(&patterns)
.map(|meta| crate::RegexSet { meta, patterns })
.map_err(Error::from_meta_build_error)
}
fn build_many_bytes(&self) -> Result<crate::bytes::RegexSet, Error> {
let metac = self
.metac
.clone()
.match_kind(MatchKind::All)
.utf8_empty(false)
.which_captures(WhichCaptures::None);
let syntaxc = self.syntaxc.clone().utf8(false);
let patterns = Arc::from(self.pats.as_slice());
meta::Builder::new()
.configure(metac)
.syntax(syntaxc)
.build_many(&patterns)
.map(|meta| crate::bytes::RegexSet { meta, patterns })
.map_err(Error::from_meta_build_error)
}
fn case_insensitive(&mut self, yes: bool) -> &mut Builder {
self.syntaxc = self.syntaxc.case_insensitive(yes);
self
}
fn multi_line(&mut self, yes: bool) -> &mut Builder {
self.syntaxc = self.syntaxc.multi_line(yes);
self
}
fn dot_matches_new_line(&mut self, yes: bool) -> &mut Builder {
self.syntaxc = self.syntaxc.dot_matches_new_line(yes);
self
}
fn crlf(&mut self, yes: bool) -> &mut Builder {
self.syntaxc = self.syntaxc.crlf(yes);
self
}
fn line_terminator(&mut self, byte: u8) -> &mut Builder {
self.metac = self.metac.clone().line_terminator(byte);
self.syntaxc = self.syntaxc.line_terminator(byte);
self
}
fn swap_greed(&mut self, yes: bool) -> &mut Builder {
self.syntaxc = self.syntaxc.swap_greed(yes);
self
}
fn ignore_whitespace(&mut self, yes: bool) -> &mut Builder {
self.syntaxc = self.syntaxc.ignore_whitespace(yes);
self
}
fn unicode(&mut self, yes: bool) -> &mut Builder {
self.syntaxc = self.syntaxc.unicode(yes);
self
}
fn octal(&mut self, yes: bool) -> &mut Builder {
self.syntaxc = self.syntaxc.octal(yes);
self
}
fn size_limit(&mut self, limit: usize) -> &mut Builder {
self.metac = self.metac.clone().nfa_size_limit(Some(limit));
self
}
fn dfa_size_limit(&mut self, limit: usize) -> &mut Builder {
self.metac = self.metac.clone().hybrid_cache_capacity(limit);
self
}
fn nest_limit(&mut self, limit: u32) -> &mut Builder {
self.syntaxc = self.syntaxc.nest_limit(limit);
self
}
}
pub(crate) mod string {
use crate::{error::Error, Regex, RegexSet};
use super::Builder;
/// A configurable builder for a [`Regex`].
///
/// This builder can be used to programmatically set flags such as `i`
/// (case insensitive) and `x` (for verbose mode). This builder can also be
/// used to configure things like the line terminator and a size limit on
/// the compiled regular expression.
#[derive(Clone, Debug)]
pub struct RegexBuilder {
builder: Builder,
}
impl RegexBuilder {
/// Create a new builder with a default configuration for the given
/// pattern.
///
/// If the pattern is invalid or exceeds the configured size limits,
/// then an error will be returned when [`RegexBuilder::build`] is
/// called.
pub fn new(pattern: &str) -> RegexBuilder {
RegexBuilder { builder: Builder::new([pattern]) }
}
/// Compiles the pattern given to `RegexBuilder::new` with the
/// configuration set on this builder.
///
/// If the pattern isn't a valid regex or if a configured size limit
/// was exceeded, then an error is returned.
pub fn build(&self) -> Result<Regex, Error> {
self.builder.build_one_string()
}
/// This configures Unicode mode for the entire pattern.
///
/// Enabling Unicode mode does a number of things:
///
/// * Most fundamentally, it causes the fundamental atom of matching
/// to be a single codepoint. When Unicode mode is disabled, it's a
/// single byte. For example, when Unicode mode is enabled, `.` will
/// match `💩` once, where as it will match 4 times when Unicode mode
/// is disabled. (Since the UTF-8 encoding of `💩` is 4 bytes long.)
/// * Case insensitive matching uses Unicode simple case folding rules.
/// * Unicode character classes like `\p{Letter}` and `\p{Greek}` are
/// available.
/// * Perl character classes are Unicode aware. That is, `\w`, `\s` and
/// `\d`.
/// * The word boundary assertions, `\b` and `\B`, use the Unicode
/// definition of a word character.
///
/// Note that if Unicode mode is disabled, then the regex will fail to
/// compile if it could match invalid UTF-8. For example, when Unicode
/// mode is disabled, then since `.` matches any byte (except for
/// `\n`), then it can match invalid UTF-8 and thus building a regex
/// from it will fail. Another example is `\w` and `\W`. Since `\w` can
/// only match ASCII bytes when Unicode mode is disabled, it's allowed.
/// But `\W` can match more than ASCII bytes, including invalid UTF-8,
/// and so it is not allowed. This restriction can be lifted only by
/// using a [`bytes::Regex`](crate::bytes::Regex).
///
/// For more details on the Unicode support in this crate, see the
/// [Unicode section](crate#unicode) in this crate's top-level
/// documentation.
///
/// The default for this is `true`.
///
/// # Example
///
/// ```
/// use regex::RegexBuilder;
///
/// let re = RegexBuilder::new(r"\w")
/// .unicode(false)
/// .build()
/// .unwrap();
/// // Normally greek letters would be included in \w, but since
/// // Unicode mode is disabled, it only matches ASCII letters.
/// assert!(!re.is_match("δ"));
///
/// let re = RegexBuilder::new(r"s")
/// .case_insensitive(true)
/// .unicode(false)
/// .build()
/// .unwrap();
/// // Normally 'ſ' is included when searching for 's' case
/// // insensitively due to Unicode's simple case folding rules. But
/// // when Unicode mode is disabled, only ASCII case insensitive rules
/// // are used.
/// assert!(!re.is_match("ſ"));
/// ```
pub fn unicode(&mut self, yes: bool) -> &mut RegexBuilder {
self.builder.unicode(yes);
self
}
/// This configures whether to enable case insensitive matching for the
/// entire pattern.
///
/// This setting can also be configured using the inline flag `i`
/// in the pattern. For example, `(?i:foo)` matches `foo` case
/// insensitively while `(?-i:foo)` matches `foo` case sensitively.
///
/// The default for this is `false`.
///
/// # Example
///
/// ```
/// use regex::RegexBuilder;
///
/// let re = RegexBuilder::new(r"foo(?-i:bar)quux")
/// .case_insensitive(true)
/// .build()
/// .unwrap();
/// assert!(re.is_match("FoObarQuUx"));
/// // Even though case insensitive matching is enabled in the builder,
/// // it can be locally disabled within the pattern. In this case,
/// // `bar` is matched case sensitively.
/// assert!(!re.is_match("fooBARquux"));
/// ```
pub fn case_insensitive(&mut self, yes: bool) -> &mut RegexBuilder {
self.builder.case_insensitive(yes);
self
}
/// This configures multi-line mode for the entire pattern.
///
/// Enabling multi-line mode changes the behavior of the `^` and `$`
/// anchor assertions. Instead of only matching at the beginning and
/// end of a haystack, respectively, multi-line mode causes them to
/// match at the beginning and end of a line *in addition* to the
/// beginning and end of a haystack. More precisely, `^` will match at
/// the position immediately following a `\n` and `$` will match at the
/// position immediately preceding a `\n`.
///
/// The behavior of this option can be impacted by other settings too:
///
/// * The [`RegexBuilder::line_terminator`] option changes `\n` above
/// to any ASCII byte.
/// * The [`RegexBuilder::crlf`] option changes the line terminator to
/// be either `\r` or `\n`, but never at the position between a `\r`
/// and `\n`.
///
/// This setting can also be configured using the inline flag `m` in
/// the pattern.
///
/// The default for this is `false`.
///
/// # Example
///
/// ```
/// use regex::RegexBuilder;
///
/// let re = RegexBuilder::new(r"^foo$")
/// .multi_line(true)
/// .build()
/// .unwrap();
/// assert_eq!(Some(1..4), re.find("\nfoo\n").map(|m| m.range()));
/// ```
pub fn multi_line(&mut self, yes: bool) -> &mut RegexBuilder {
self.builder.multi_line(yes);
self
}
/// This configures dot-matches-new-line mode for the entire pattern.
///
/// Perhaps surprisingly, the default behavior for `.` is not to match
/// any character, but rather, to match any character except for the
/// line terminator (which is `\n` by default). When this mode is
/// enabled, the behavior changes such that `.` truly matches any
/// character.
///
/// This setting can also be configured using the inline flag `s` in
/// the pattern. For example, `(?s:.)` and `\p{any}` are equivalent
/// regexes.
///
/// The default for this is `false`.
///
/// # Example
///
/// ```
/// use regex::RegexBuilder;
///
/// let re = RegexBuilder::new(r"foo.bar")
/// .dot_matches_new_line(true)
/// .build()
/// .unwrap();
/// let hay = "foo\nbar";
/// assert_eq!(Some("foo\nbar"), re.find(hay).map(|m| m.as_str()));
/// ```
pub fn dot_matches_new_line(
&mut self,
yes: bool,
) -> &mut RegexBuilder {
self.builder.dot_matches_new_line(yes);
self
}
/// This configures CRLF mode for the entire pattern.
///
/// When CRLF mode is enabled, both `\r` ("carriage return" or CR for
/// short) and `\n` ("line feed" or LF for short) are treated as line
/// terminators. This results in the following:
///
/// * Unless dot-matches-new-line mode is enabled, `.` will now match
/// any character except for `\n` and `\r`.
/// * When multi-line mode is enabled, `^` will match immediately
/// following a `\n` or a `\r`. Similarly, `$` will match immediately
/// preceding a `\n` or a `\r`. Neither `^` nor `$` will ever match
/// between `\r` and `\n`.
///
/// This setting can also be configured using the inline flag `R` in
/// the pattern.
///
/// The default for this is `false`.
///
/// # Example
///
/// ```
/// use regex::RegexBuilder;
///
/// let re = RegexBuilder::new(r"^foo$")
/// .multi_line(true)
/// .crlf(true)
/// .build()
/// .unwrap();
/// let hay = "\r\nfoo\r\n";
/// // If CRLF mode weren't enabled here, then '$' wouldn't match
/// // immediately after 'foo', and thus no match would be found.
/// assert_eq!(Some("foo"), re.find(hay).map(|m| m.as_str()));
/// ```
///
/// This example demonstrates that `^` will never match at a position
/// between `\r` and `\n`. (`$` will similarly not match between a `\r`
/// and a `\n`.)
///
/// ```
/// use regex::RegexBuilder;
///
/// let re = RegexBuilder::new(r"^")
/// .multi_line(true)
/// .crlf(true)
/// .build()
/// .unwrap();
/// let hay = "\r\n\r\n";
/// let ranges: Vec<_> = re.find_iter(hay).map(|m| m.range()).collect();
/// assert_eq!(ranges, vec![0..0, 2..2, 4..4]);
/// ```
pub fn crlf(&mut self, yes: bool) -> &mut RegexBuilder {
self.builder.crlf(yes);
self
}
/// Configures the line terminator to be used by the regex.
///
/// The line terminator is relevant in two ways for a particular regex:
///
/// * When dot-matches-new-line mode is *not* enabled (the default),
/// then `.` will match any character except for the configured line
/// terminator.
/// * When multi-line mode is enabled (not the default), then `^` and
/// `$` will match immediately after and before, respectively, a line
/// terminator.
///
/// In both cases, if CRLF mode is enabled in a particular context,
/// then it takes precedence over any configured line terminator.
///
/// This option cannot be configured from within the pattern.
///
/// The default line terminator is `\n`.
///
/// # Example
///
/// This shows how to treat the NUL byte as a line terminator. This can
/// be a useful heuristic when searching binary data.
///
/// ```
/// use regex::RegexBuilder;
///
/// let re = RegexBuilder::new(r"^foo$")
/// .multi_line(true)
/// .line_terminator(b'\x00')
/// .build()
/// .unwrap();
/// let hay = "\x00foo\x00";
/// assert_eq!(Some(1..4), re.find(hay).map(|m| m.range()));
/// ```
///
/// This example shows that the behavior of `.` is impacted by this
/// setting as well:
///
/// ```
/// use regex::RegexBuilder;
///
/// let re = RegexBuilder::new(r".")
/// .line_terminator(b'\x00')
/// .build()
/// .unwrap();
/// assert!(re.is_match("\n"));
/// assert!(!re.is_match("\x00"));
/// ```
///
/// This shows that building a regex will fail if the byte given
/// is not ASCII and the pattern could result in matching invalid
/// UTF-8. This is because any singular non-ASCII byte is not valid
/// UTF-8, and it is not permitted for a [`Regex`] to match invalid
/// UTF-8. (It is permissible to use a non-ASCII byte when building a
/// [`bytes::Regex`](crate::bytes::Regex).)
///
/// ```
/// use regex::RegexBuilder;
///
/// assert!(RegexBuilder::new(r".").line_terminator(0x80).build().is_err());
/// // Note that using a non-ASCII byte isn't enough on its own to
/// // cause regex compilation to fail. You actually have to make use
/// // of it in the regex in a way that leads to matching invalid
/// // UTF-8. If you don't, then regex compilation will succeed!
/// assert!(RegexBuilder::new(r"a").line_terminator(0x80).build().is_ok());
/// ```
pub fn line_terminator(&mut self, byte: u8) -> &mut RegexBuilder {
self.builder.line_terminator(byte);
self
}
/// This configures swap-greed mode for the entire pattern.
///
/// When swap-greed mode is enabled, patterns like `a+` will become
/// non-greedy and patterns like `a+?` will become greedy. In other
/// words, the meanings of `a+` and `a+?` are switched.
///
/// This setting can also be configured using the inline flag `U` in
/// the pattern.
///
/// The default for this is `false`.
///
/// # Example
///
/// ```
/// use regex::RegexBuilder;
///
/// let re = RegexBuilder::new(r"a+")
/// .swap_greed(true)
/// .build()
/// .unwrap();
/// assert_eq!(Some("a"), re.find("aaa").map(|m| m.as_str()));
/// ```
pub fn swap_greed(&mut self, yes: bool) -> &mut RegexBuilder {
self.builder.swap_greed(yes);
self
}
/// This configures verbose mode for the entire pattern.
///
/// When enabled, whitespace will treated as insignifcant in the
/// pattern and `#` can be used to start a comment until the next new
/// line.
///
/// Normally, in most places in a pattern, whitespace is treated
/// literally. For example ` +` will match one or more ASCII whitespace
/// characters.
///
/// When verbose mode is enabled, `\#` can be used to match a literal
/// `#` and `\ ` can be used to match a literal ASCII whitespace
/// character.
///
/// Verbose mode is useful for permitting regexes to be formatted and
/// broken up more nicely. This may make them more easily readable.
///
/// This setting can also be configured using the inline flag `x` in
/// the pattern.
///
/// The default for this is `false`.
///
/// # Example
///
/// ```
/// use regex::RegexBuilder;
///
/// let pat = r"
/// \b
/// (?<first>\p{Uppercase}\w*) # always start with uppercase letter
/// [\s--\n]+ # whitespace should separate names
/// (?: # middle name can be an initial!
/// (?:(?<initial>\p{Uppercase})\.|(?<middle>\p{Uppercase}\w*))
/// [\s--\n]+
/// )?
/// (?<last>\p{Uppercase}\w*)
/// \b
/// ";
/// let re = RegexBuilder::new(pat)
/// .ignore_whitespace(true)
/// .build()
/// .unwrap();
///
/// let caps = re.captures("Harry Potter").unwrap();
/// assert_eq!("Harry", &caps["first"]);
/// assert_eq!("Potter", &caps["last"]);
///
/// let caps = re.captures("Harry J. Potter").unwrap();
/// assert_eq!("Harry", &caps["first"]);
/// // Since a middle name/initial isn't required for an overall match,
/// // we can't assume that 'initial' or 'middle' will be populated!
/// assert_eq!(Some("J"), caps.name("initial").map(|m| m.as_str()));
/// assert_eq!(None, caps.name("middle").map(|m| m.as_str()));
/// assert_eq!("Potter", &caps["last"]);
///
/// let caps = re.captures("Harry James Potter").unwrap();
/// assert_eq!("Harry", &caps["first"]);
/// // Since a middle name/initial isn't required for an overall match,
/// // we can't assume that 'initial' or 'middle' will be populated!
/// assert_eq!(None, caps.name("initial").map(|m| m.as_str()));
/// assert_eq!(Some("James"), caps.name("middle").map(|m| m.as_str()));
/// assert_eq!("Potter", &caps["last"]);
/// ```
pub fn ignore_whitespace(&mut self, yes: bool) -> &mut RegexBuilder {
self.builder.ignore_whitespace(yes);
self
}
/// This configures octal mode for the entire pattern.
///
/// Octal syntax is a little-known way of uttering Unicode codepoints
/// in a pattern. For example, `a`, `\x61`, `\u0061` and `\141` are all
/// equivalent patterns, where the last example shows octal syntax.
///
/// While supporting octal syntax isn't in and of itself a problem,
/// it does make good error messages harder. That is, in PCRE based
/// regex engines, syntax like `\1` invokes a backreference, which is
/// explicitly unsupported this library. However, many users expect
/// backreferences to be supported. Therefore, when octal support
/// is disabled, the error message will explicitly mention that
/// backreferences aren't supported.
///
/// The default for this is `false`.
///
/// # Example
///
/// ```
/// use regex::RegexBuilder;
///
/// // Normally this pattern would not compile, with an error message
/// // about backreferences not being supported. But with octal mode
/// // enabled, octal escape sequences work.
/// let re = RegexBuilder::new(r"\141")
/// .octal(true)
/// .build()
/// .unwrap();
/// assert!(re.is_match("a"));
/// ```
pub fn octal(&mut self, yes: bool) -> &mut RegexBuilder {
self.builder.octal(yes);
self
}
/// Sets the approximate size limit, in bytes, of the compiled regex.
///
/// This roughly corresponds to the number of heap memory, in
/// bytes, occupied by a single regex. If the regex would otherwise
/// approximately exceed this limit, then compiling that regex will
/// fail.
///
/// The main utility of a method like this is to avoid compiling
/// regexes that use an unexpected amount of resources, such as
/// time and memory. Even if the memory usage of a large regex is
/// acceptable, its search time may not be. Namely, worst case time
/// complexity for search is `O(m * n)`, where `m ~ len(pattern)` and
/// `n ~ len(haystack)`. That is, search time depends, in part, on the
/// size of the compiled regex. This means that putting a limit on the
/// size of the regex limits how much a regex can impact search time.
///
/// For more information about regex size limits, see the section on
/// [untrusted inputs](crate#untrusted-input) in the top-level crate
/// documentation.
///
/// The default for this is some reasonable number that permits most
/// patterns to compile successfully.
///
/// # Example
///
/// ```
/// # if !cfg!(target_pointer_width = "64") { return; } // see #1041
/// use regex::RegexBuilder;
///
/// // It may surprise you how big some seemingly small patterns can
/// // be! Since \w is Unicode aware, this generates a regex that can
/// // match approximately 140,000 distinct codepoints.
/// assert!(RegexBuilder::new(r"\w").size_limit(45_000).build().is_err());
/// ```
pub fn size_limit(&mut self, bytes: usize) -> &mut RegexBuilder {
self.builder.size_limit(bytes);
self
}
/// Set the approximate capacity, in bytes, of the cache of transitions
/// used by the lazy DFA.
///
/// While the lazy DFA isn't always used, in tends to be the most
/// commonly use regex engine in default configurations. It tends to
/// adopt the performance profile of a fully build DFA, but without the
/// downside of taking worst case exponential time to build.
///
/// The downside is that it needs to keep a cache of transitions and
/// states that are built while running a search, and this cache
/// can fill up. When it fills up, the cache will reset itself. Any
/// previously generated states and transitions will then need to be
/// re-generated. If this happens too many times, then this library
/// will bail out of using the lazy DFA and switch to a different regex
/// engine.
///
/// If your regex provokes this particular downside of the lazy DFA,
/// then it may be beneficial to increase its cache capacity. This will
/// potentially reduce the frequency of cache resetting (ideally to
/// `0`). While it won't fix all potential performance problems with
/// the lazy DFA, increasing the cache capacity does fix some.
///
/// There is no easy way to determine, a priori, whether increasing
/// this cache capacity will help. In general, the larger your regex,
/// the more cache it's likely to use. But that isn't an ironclad rule.
/// For example, a regex like `[01]*1[01]{N}` would normally produce a
/// fully build DFA that is exponential in size with respect to `N`.
/// The lazy DFA will prevent exponential space blow-up, but it cache
/// is likely to fill up, even when it's large and even for smallish
/// values of `N`.
///
/// If you aren't sure whether this helps or not, it is sensible to
/// set this to some arbitrarily large number in testing, such as
/// `usize::MAX`. Namely, this represents the amount of capacity that
/// *may* be used. It's probably not a good idea to use `usize::MAX` in
/// production though, since it implies there are no controls on heap
/// memory used by this library during a search. In effect, set it to
/// whatever you're willing to allocate for a single regex search.
pub fn dfa_size_limit(&mut self, bytes: usize) -> &mut RegexBuilder {
self.builder.dfa_size_limit(bytes);
self
}
/// Set the nesting limit for this parser.
///
/// The nesting limit controls how deep the abstract syntax tree is
/// allowed to be. If the AST exceeds the given limit (e.g., with too
/// many nested groups), then an error is returned by the parser.
///
/// The purpose of this limit is to act as a heuristic to prevent stack
/// overflow for consumers that do structural induction on an AST using
/// explicit recursion. While this crate never does this (instead using
/// constant stack space and moving the call stack to the heap), other
/// crates may.
///
/// This limit is not checked until the entire AST is parsed.
/// Therefore, if callers want to put a limit on the amount of heap
/// space used, then they should impose a limit on the length, in
/// bytes, of the concrete pattern string. In particular, this is
/// viable since this parser implementation will limit itself to heap
/// space proportional to the length of the pattern string. See also
/// the [untrusted inputs](crate#untrusted-input) section in the
/// top-level crate documentation for more information about this.
///
/// Note that a nest limit of `0` will return a nest limit error for
/// most patterns but not all. For example, a nest limit of `0` permits
/// `a` but not `ab`, since `ab` requires an explicit concatenation,
/// which results in a nest depth of `1`. In general, a nest limit is
/// not something that manifests in an obvious way in the concrete
/// syntax, therefore, it should not be used in a granular way.
///
/// # Example
///
/// ```
/// use regex::RegexBuilder;
///
/// assert!(RegexBuilder::new(r"a").nest_limit(0).build().is_ok());
/// assert!(RegexBuilder::new(r"ab").nest_limit(0).build().is_err());
/// ```
pub fn nest_limit(&mut self, limit: u32) -> &mut RegexBuilder {
self.builder.nest_limit(limit);
self
}
}
/// A configurable builder for a [`RegexSet`].
///
/// This builder can be used to programmatically set flags such as
/// `i` (case insensitive) and `x` (for verbose mode). This builder
/// can also be used to configure things like the line terminator
/// and a size limit on the compiled regular expression.
#[derive(Clone, Debug)]
pub struct RegexSetBuilder {
builder: Builder,
}
impl RegexSetBuilder {
/// Create a new builder with a default configuration for the given
/// patterns.
///
/// If the patterns are invalid or exceed the configured size limits,
/// then an error will be returned when [`RegexSetBuilder::build`] is
/// called.
pub fn new<I, S>(patterns: I) -> RegexSetBuilder
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
RegexSetBuilder { builder: Builder::new(patterns) }
}
/// Compiles the patterns given to `RegexSetBuilder::new` with the
/// configuration set on this builder.
///
/// If the patterns aren't valid regexes or if a configured size limit
/// was exceeded, then an error is returned.
pub fn build(&self) -> Result<RegexSet, Error> {
self.builder.build_many_string()
}
/// This configures Unicode mode for the all of the patterns.
///
/// Enabling Unicode mode does a number of things:
///
/// * Most fundamentally, it causes the fundamental atom of matching
/// to be a single codepoint. When Unicode mode is disabled, it's a
/// single byte. For example, when Unicode mode is enabled, `.` will
/// match `💩` once, where as it will match 4 times when Unicode mode
/// is disabled. (Since the UTF-8 encoding of `💩` is 4 bytes long.)
/// * Case insensitive matching uses Unicode simple case folding rules.
/// * Unicode character classes like `\p{Letter}` and `\p{Greek}` are
/// available.
/// * Perl character classes are Unicode aware. That is, `\w`, `\s` and
/// `\d`.
/// * The word boundary assertions, `\b` and `\B`, use the Unicode
/// definition of a word character.
///
/// Note that if Unicode mode is disabled, then the regex will fail to
/// compile if it could match invalid UTF-8. For example, when Unicode
/// mode is disabled, then since `.` matches any byte (except for
/// `\n`), then it can match invalid UTF-8 and thus building a regex
/// from it will fail. Another example is `\w` and `\W`. Since `\w` can
/// only match ASCII bytes when Unicode mode is disabled, it's allowed.
/// But `\W` can match more than ASCII bytes, including invalid UTF-8,
/// and so it is not allowed. This restriction can be lifted only by
/// using a [`bytes::RegexSet`](crate::bytes::RegexSet).
///
/// For more details on the Unicode support in this crate, see the
/// [Unicode section](crate#unicode) in this crate's top-level
/// documentation.
///
/// The default for this is `true`.
///
/// # Example
///
/// ```
/// use regex::RegexSetBuilder;
///
/// let re = RegexSetBuilder::new([r"\w"])
/// .unicode(false)
/// .build()
/// .unwrap();
/// // Normally greek letters would be included in \w, but since
/// // Unicode mode is disabled, it only matches ASCII letters.
/// assert!(!re.is_match("δ"));
///
/// let re = RegexSetBuilder::new([r"s"])
/// .case_insensitive(true)
/// .unicode(false)
/// .build()
/// .unwrap();
/// // Normally 'ſ' is included when searching for 's' case
/// // insensitively due to Unicode's simple case folding rules. But
/// // when Unicode mode is disabled, only ASCII case insensitive rules
/// // are used.
/// assert!(!re.is_match("ſ"));
/// ```
pub fn unicode(&mut self, yes: bool) -> &mut RegexSetBuilder {
self.builder.unicode(yes);
self
}
/// This configures whether to enable case insensitive matching for all
/// of the patterns.
///
/// This setting can also be configured using the inline flag `i`
/// in the pattern. For example, `(?i:foo)` matches `foo` case
/// insensitively while `(?-i:foo)` matches `foo` case sensitively.
///
/// The default for this is `false`.
///
/// # Example
///
/// ```
/// use regex::RegexSetBuilder;
///
/// let re = RegexSetBuilder::new([r"foo(?-i:bar)quux"])
/// .case_insensitive(true)
/// .build()
/// .unwrap();
/// assert!(re.is_match("FoObarQuUx"));
/// // Even though case insensitive matching is enabled in the builder,
/// // it can be locally disabled within the pattern. In this case,
/// // `bar` is matched case sensitively.
/// assert!(!re.is_match("fooBARquux"));
/// ```
pub fn case_insensitive(&mut self, yes: bool) -> &mut RegexSetBuilder {
self.builder.case_insensitive(yes);
self
}
/// This configures multi-line mode for all of the patterns.
///
/// Enabling multi-line mode changes the behavior of the `^` and `$`
/// anchor assertions. Instead of only matching at the beginning and
/// end of a haystack, respectively, multi-line mode causes them to
/// match at the beginning and end of a line *in addition* to the
/// beginning and end of a haystack. More precisely, `^` will match at
/// the position immediately following a `\n` and `$` will match at the
/// position immediately preceding a `\n`.
///
/// The behavior of this option can be impacted by other settings too:
///
/// * The [`RegexSetBuilder::line_terminator`] option changes `\n`
/// above to any ASCII byte.
/// * The [`RegexSetBuilder::crlf`] option changes the line terminator
/// to be either `\r` or `\n`, but never at the position between a `\r`
/// and `\n`.
///
/// This setting can also be configured using the inline flag `m` in
/// the pattern.
///
/// The default for this is `false`.
///
/// # Example
///
/// ```
/// use regex::RegexSetBuilder;
///
/// let re = RegexSetBuilder::new([r"^foo$"])
/// .multi_line(true)
/// .build()
/// .unwrap();
/// assert!(re.is_match("\nfoo\n"));
/// ```
pub fn multi_line(&mut self, yes: bool) -> &mut RegexSetBuilder {
self.builder.multi_line(yes);
self
}
/// This configures dot-matches-new-line mode for the entire pattern.
///
/// Perhaps surprisingly, the default behavior for `.` is not to match
/// any character, but rather, to match any character except for the
/// line terminator (which is `\n` by default). When this mode is
/// enabled, the behavior changes such that `.` truly matches any
/// character.
///
/// This setting can also be configured using the inline flag `s` in
/// the pattern. For example, `(?s:.)` and `\p{any}` are equivalent
/// regexes.
///
/// The default for this is `false`.
///
/// # Example
///
/// ```
/// use regex::RegexSetBuilder;
///
/// let re = RegexSetBuilder::new([r"foo.bar"])
/// .dot_matches_new_line(true)
/// .build()
/// .unwrap();
/// let hay = "foo\nbar";
/// assert!(re.is_match(hay));
/// ```
pub fn dot_matches_new_line(
&mut self,
yes: bool,
) -> &mut RegexSetBuilder {
self.builder.dot_matches_new_line(yes);
self
}
/// This configures CRLF mode for all of the patterns.
///
/// When CRLF mode is enabled, both `\r` ("carriage return" or CR for
/// short) and `\n` ("line feed" or LF for short) are treated as line
/// terminators. This results in the following:
///
/// * Unless dot-matches-new-line mode is enabled, `.` will now match
/// any character except for `\n` and `\r`.
/// * When multi-line mode is enabled, `^` will match immediately
/// following a `\n` or a `\r`. Similarly, `$` will match immediately
/// preceding a `\n` or a `\r`. Neither `^` nor `$` will ever match
/// between `\r` and `\n`.
///
/// This setting can also be configured using the inline flag `R` in
/// the pattern.
///
/// The default for this is `false`.
///
/// # Example
///
/// ```
/// use regex::RegexSetBuilder;