@@ -416,10 +416,20 @@ where
416
416
if eq ( & self . 0 , "int" ) {
417
417
Left ( r#"((?:-?\d+)|(?:\d+))"# . chars ( ) . map ( Ok ) )
418
418
} else if eq ( & self . 0 , "float" ) {
419
+ // Regex in other implementations has lookaheads. As `regex` crate
420
+ // doesn't support them, we use `f32`/`f64` grammar instead:
421
+ // https://doc.rust-lang.org/stable/std/primitive.f64.html#grammar
422
+ // Provided grammar is a superset of the original one:
423
+ // - supports `e` as exponent in addition to `E`
424
+ // - supports trailing comma: `1.`
425
+ // - supports `inf` and `NaN`
419
426
Left (
420
- r#"((?=.*\d.*)[-+]?\d*(?:\.(?=\d.*))?\d*(?:\d+[E][+-]?\d+)?)"#
421
- . chars ( )
422
- . map ( Ok ) ,
427
+ "([+-]?(?:inf\
428
+ |NaN\
429
+ |(?:\\ d+|\\ d+\\ .\\ d*|\\ d*\\ .\\ d+)(?:[eE][+-]?\\ d+)?\
430
+ ))"
431
+ . chars ( )
432
+ . map ( Ok ) ,
423
433
)
424
434
} else if eq ( & self . 0 , "word" ) {
425
435
Left ( r#"([^\s]+)"# . chars ( ) . map ( Ok ) )
@@ -592,6 +602,11 @@ mod spec {
592
602
. unwrap_or_else ( |e| panic ! ( "failed: {}" , e) ) ;
593
603
594
604
assert_eq ! ( expr. as_str( ) , "^(?:a|b) (?:c|d|e)$" ) ;
605
+ assert ! ( expr. is_match( "a c" ) ) ;
606
+ assert ! ( expr. is_match( "b e" ) ) ;
607
+ assert ! ( !expr. is_match( "c e" ) ) ;
608
+ assert ! ( !expr. is_match( "a" ) ) ;
609
+ assert ! ( !expr. is_match( "a " ) ) ;
595
610
}
596
611
597
612
#[ test]
@@ -600,14 +615,17 @@ mod spec {
600
615
Expression :: regex ( "" ) . unwrap_or_else ( |e| panic ! ( "failed: {}" , e) ) ;
601
616
602
617
assert_eq ! ( expr. as_str( ) , "^$" ) ;
618
+ assert ! ( expr. is_match( "" ) ) ;
619
+ assert ! ( !expr. is_match( "a" ) ) ;
603
620
}
604
621
605
622
#[ test]
606
623
fn escape_regex_characters ( ) {
607
- let expr = Expression :: regex ( r"^$[]\(\) {}\\.|?*+" )
624
+ let expr = Expression :: regex ( r"^$[]\()\ {}\\.|?*+" )
608
625
. unwrap_or_else ( |e| panic ! ( "failed: {}" , e) ) ;
609
626
610
- assert_eq ! ( expr. as_str( ) , r"^\^\$\[\]\(\)(.*)\\\.\|\?\*\+$" ) ;
627
+ assert_eq ! ( expr. as_str( ) , r"^\^\$\[\]\(\)\{\}\\\.\|\?\*\+$" ) ;
628
+ assert ! ( expr. is_match( "^$[](){}\\ .|?*+" ) ) ;
611
629
}
612
630
613
631
#[ test]
@@ -616,14 +634,80 @@ mod spec {
616
634
. unwrap_or_else ( |e| panic ! ( "failed: {}" , e) ) ;
617
635
618
636
assert_eq ! ( expr. as_str( ) , "^(?:a)?$" ) ;
637
+ assert ! ( expr. is_match( "" ) ) ;
638
+ assert ! ( expr. is_match( "a" ) ) ;
639
+ assert ! ( !expr. is_match( "b" ) ) ;
619
640
}
620
641
621
642
#[ test]
622
- fn parameter ( ) {
643
+ fn parameter_int ( ) {
623
644
let expr = Expression :: regex ( "{int}" )
624
645
. unwrap_or_else ( |e| panic ! ( "failed: {}" , e) ) ;
625
646
626
647
assert_eq ! ( expr. as_str( ) , "^((?:-?\\ d+)|(?:\\ d+))$" ) ;
648
+ assert ! ( expr. is_match( "123" ) ) ;
649
+ assert ! ( expr. is_match( "-123" ) ) ;
650
+ assert ! ( !expr. is_match( "+123" ) ) ;
651
+ assert ! ( !expr. is_match( "123." ) ) ;
652
+ }
653
+
654
+ #[ test]
655
+ fn parameter_float ( ) {
656
+ let expr = Expression :: regex ( "{float}" )
657
+ . unwrap_or_else ( |e| panic ! ( "failed: {}" , e) ) ;
658
+
659
+ assert_eq ! (
660
+ expr. as_str( ) ,
661
+ "^([+-]?(?:inf\
662
+ |NaN\
663
+ |(?:\\ d+|\\ d+\\ .\\ d*|\\ d*\\ .\\ d+)(?:[eE][+-]?\\ d+)?\
664
+ ))$",
665
+ ) ;
666
+ assert ! ( expr. is_match( "+1" ) ) ;
667
+ assert ! ( expr. is_match( ".1" ) ) ;
668
+ assert ! ( expr. is_match( "-.1" ) ) ;
669
+ assert ! ( expr. is_match( "-1." ) ) ;
670
+ assert ! ( expr. is_match( "-1.1E+1" ) ) ;
671
+ assert ! ( expr. is_match( "-inf" ) ) ;
672
+ assert ! ( expr. is_match( "NaN" ) ) ;
673
+ }
674
+
675
+ #[ test]
676
+ fn parameter_word ( ) {
677
+ let expr = Expression :: regex ( "{word}" )
678
+ . unwrap_or_else ( |e| panic ! ( "failed: {}" , e) ) ;
679
+
680
+ assert_eq ! ( expr. as_str( ) , "^([^\\ s]+)$" ) ;
681
+ assert ! ( expr. is_match( "test" ) ) ;
682
+ assert ! ( expr. is_match( "\" test\" " ) ) ;
683
+ assert ! ( !expr. is_match( "with space" ) ) ;
684
+ }
685
+
686
+ #[ test]
687
+ fn parameter_string ( ) {
688
+ let expr = Expression :: regex ( "{string}" )
689
+ . unwrap_or_else ( |e| panic ! ( "failed: {}" , e) ) ;
690
+
691
+ assert_eq ! (
692
+ expr. as_str( ) ,
693
+ r#"^("(?:[^"\\]*(?:\\.[^"\\]*)*)"|'(?:[^'\\]*(?:\\.[^'\\]*)*)')$"# ,
694
+ ) ;
695
+ assert ! ( expr. is_match( "\" \" " ) ) ;
696
+ assert ! ( expr. is_match( "''" ) ) ;
697
+ assert ! ( expr. is_match( "'with \" '" ) ) ;
698
+ assert ! ( expr. is_match( "\" with '\" " ) ) ;
699
+ assert ! ( expr. is_match( "\" with \\ \" escaped\" " ) ) ;
700
+ assert ! ( expr. is_match( "'with \\ ' escaped'" ) ) ;
701
+ assert ! ( !expr. is_match( "word" ) ) ;
702
+ }
703
+
704
+ #[ test]
705
+ fn parameter_all ( ) {
706
+ let expr =
707
+ Expression :: regex ( "{}" ) . unwrap_or_else ( |e| panic ! ( "failed: {}" , e) ) ;
708
+
709
+ assert_eq ! ( expr. as_str( ) , "^(.*)$" ) ;
710
+ assert ! ( expr. is_match( "anything matches" ) ) ;
627
711
}
628
712
629
713
#[ test]
@@ -632,6 +716,9 @@ mod spec {
632
716
Expression :: regex ( "a" ) . unwrap_or_else ( |e| panic ! ( "failed: {}" , e) ) ;
633
717
634
718
assert_eq ! ( expr. as_str( ) , "^a$" ) ;
719
+ assert ! ( expr. is_match( "a" ) ) ;
720
+ assert ! ( !expr. is_match( "b" ) ) ;
721
+ assert ! ( !expr. is_match( "ab" ) ) ;
635
722
}
636
723
637
724
#[ allow( clippy:: non_ascii_literal) ]
@@ -641,6 +728,9 @@ mod spec {
641
728
. unwrap_or_else ( |e| panic ! ( "failed: {}" , e) ) ;
642
729
643
730
assert_eq ! ( expr. as_str( ) , "^Привет, Мир(?:ы)?!$" ) ;
731
+ assert ! ( expr. is_match( "Привет, Мир!" ) ) ;
732
+ assert ! ( expr. is_match( "Привет, Миры!" ) ) ;
733
+ assert ! ( !expr. is_match( "Hello world" ) ) ;
644
734
}
645
735
646
736
#[ test]
0 commit comments