@@ -14,6 +14,8 @@ use std::ops::Index;
14
14
#[ cfg( feature = "pattern" ) ]
15
15
use std:: str:: pattern:: { Pattern , Searcher , SearchStep } ;
16
16
use std:: str:: FromStr ;
17
+ use std:: collections:: HashMap ;
18
+ use std:: sync:: Arc ;
17
19
18
20
use program:: { Program , MatchEngine } ;
19
21
use syntax;
@@ -416,13 +418,13 @@ impl Regex {
416
418
///
417
419
/// The `0`th capture group is always unnamed, so it must always be
418
420
/// accessed with `at(0)` or `[0]`.
419
- pub fn captures < ' r , ' t > ( & ' r self , text : & ' t str ) -> Option < Captures < ' r , ' t > > {
421
+ pub fn captures < ' t > ( & self , text : & ' t str ) -> Option < Captures < ' t > > {
420
422
let mut locs = self . alloc_captures ( ) ;
421
423
if exec ( self , & mut locs, text, 0 ) {
422
424
Some ( Captures {
423
- regex : self ,
424
425
text : text,
425
426
locs : locs,
427
+ named_groups : NamedGroups :: from_regex ( self )
426
428
} )
427
429
} else {
428
430
None
@@ -816,6 +818,47 @@ impl<'r, 't> Iterator for RegexSplitsN<'r, 't> {
816
818
}
817
819
}
818
820
821
+ enum NamedGroups {
822
+ Native ( & ' static [ ( & ' static str , usize ) ] ) ,
823
+ Dynamic ( Arc < HashMap < String , usize > > ) ,
824
+ }
825
+
826
+ impl NamedGroups {
827
+ fn from_regex ( regex : & Regex ) -> NamedGroups {
828
+ match * regex {
829
+ Regex :: Native ( ExNative { ref groups, .. } ) =>
830
+ NamedGroups :: Native ( groups) ,
831
+ Regex :: Dynamic ( Program { ref named_groups, .. } ) =>
832
+ NamedGroups :: Dynamic ( named_groups. clone ( ) )
833
+ }
834
+ }
835
+
836
+ fn pos ( & self , name : & str ) -> Option < usize > {
837
+ match * self {
838
+ NamedGroups :: Native ( groups) => {
839
+ groups. binary_search_by ( |& ( n, _) | n. cmp ( name) )
840
+ . ok ( ) . map ( |i| groups[ i] . 1 )
841
+ } ,
842
+ NamedGroups :: Dynamic ( ref groups) => {
843
+ groups. get ( name) . map ( |i| * i)
844
+ } ,
845
+ }
846
+ }
847
+
848
+ fn iter < ' n > ( & ' n self ) -> Box < Iterator < Item =( & ' n str , usize ) > + ' n > {
849
+ match * self {
850
+ NamedGroups :: Native ( groups) => {
851
+ Box :: new ( groups. iter ( ) . map ( |& v| v) )
852
+ as Box < Iterator < Item =( & ' n str , usize ) > + ' n >
853
+ } ,
854
+ NamedGroups :: Dynamic ( ref groups) => {
855
+ Box :: new ( groups. iter ( ) . map ( |( s, i) | ( & s[ ..] , * i) ) )
856
+ as Box < Iterator < Item =( & ' n str , usize ) > + ' n >
857
+ } ,
858
+ }
859
+ }
860
+ }
861
+
819
862
/// Captures represents a group of captured strings for a single match.
820
863
///
821
864
/// The 0th capture always corresponds to the entire match. Each subsequent
@@ -827,13 +870,13 @@ impl<'r, 't> Iterator for RegexSplitsN<'r, 't> {
827
870
/// Positions returned from a capture group are always byte indices.
828
871
///
829
872
/// `'t` is the lifetime of the matched text.
830
- pub struct Captures < ' r , ' t > {
831
- regex : & ' r Regex ,
873
+ pub struct Captures < ' t > {
832
874
text : & ' t str ,
833
875
locs : Vec < Option < usize > > ,
876
+ named_groups : NamedGroups ,
834
877
}
835
878
836
- impl < ' r , ' t > Captures < ' r , ' t > {
879
+ impl < ' t > Captures < ' t > {
837
880
/// Returns the start and end positions of the Nth capture group.
838
881
/// Returns `None` if `i` is not a valid capture group or if the capture
839
882
/// group did not match anything.
@@ -862,49 +905,29 @@ impl<'r, 't> Captures<'r, 't> {
862
905
/// `name` isn't a valid capture group or didn't match anything, then
863
906
/// `None` is returned.
864
907
pub fn name ( & self , name : & str ) -> Option < & ' t str > {
865
- match * self . regex {
866
- Regex :: Native ( ExNative { ref groups, .. } ) => {
867
- match groups. binary_search_by ( |& ( n, _) | n. cmp ( name) ) {
868
- Ok ( i) => self . at ( groups[ i] . 1 ) ,
869
- Err ( _) => None
870
- }
871
- } ,
872
- Regex :: Dynamic ( Program { ref named_groups, .. } ) => {
873
- named_groups. get ( name) . and_then ( |i| self . at ( * i) )
874
- } ,
875
- }
908
+ self . named_groups . pos ( name) . and_then ( |i| self . at ( i) )
876
909
}
877
910
878
911
/// Creates an iterator of all the capture groups in order of appearance
879
912
/// in the regular expression.
880
- pub fn iter < ' c > ( & ' c self ) -> SubCaptures < ' c , ' r , ' t > {
913
+ pub fn iter < ' c > ( & ' c self ) -> SubCaptures < ' c , ' t > {
881
914
SubCaptures { idx : 0 , caps : self , }
882
915
}
883
916
884
917
/// Creates an iterator of all the capture group positions in order of
885
918
/// appearance in the regular expression. Positions are byte indices
886
919
/// in terms of the original string matched.
887
- pub fn iter_pos < ' c > ( & ' c self ) -> SubCapturesPos < ' c , ' r , ' t > {
888
- SubCapturesPos { idx : 0 , caps : self , }
920
+ pub fn iter_pos < ' c > ( & ' c self ) -> SubCapturesPos < ' c > {
921
+ SubCapturesPos { idx : 0 , locs : & self . locs }
889
922
}
890
923
891
924
/// Creates an iterator of all named groups as an tuple with the group
892
925
/// name and the value. The iterator returns these values in arbitrary
893
926
/// order.
894
- pub fn iter_named < ' c > ( & ' c self ) -> SubCapturesNamed < ' c , ' r , ' t > {
895
- let iter = match * self . regex {
896
- Regex :: Native ( ExNative { ref groups, .. } ) => {
897
- Box :: new ( groups. iter ( ) . map ( |& v| v) )
898
- as Box < Iterator < Item =( & ' r str , usize ) > + ' r >
899
- } ,
900
- Regex :: Dynamic ( Program { ref named_groups, .. } ) => {
901
- Box :: new ( named_groups. iter ( ) . map ( |( s, i) | ( & s[ ..] , * i) ) )
902
- as Box < Iterator < Item =( & ' r str , usize ) > + ' r >
903
- } ,
904
- } ;
927
+ pub fn iter_named < ' c : ' t > ( & ' c self ) -> SubCapturesNamed < ' c , ' t > {
905
928
SubCapturesNamed {
906
929
caps : self ,
907
- inner : iter
930
+ names : self . named_groups . iter ( )
908
931
}
909
932
}
910
933
@@ -948,7 +971,7 @@ impl<'r, 't> Captures<'r, 't> {
948
971
///
949
972
/// # Panics
950
973
/// If there is no group at the given index.
951
- impl < ' r , ' t > Index < usize > for Captures < ' r , ' t > {
974
+ impl < ' t > Index < usize > for Captures < ' t > {
952
975
953
976
type Output = str ;
954
977
@@ -962,7 +985,7 @@ impl<'r, 't> Index<usize> for Captures<'r, 't> {
962
985
///
963
986
/// # Panics
964
987
/// If there is no group named by the given value.
965
- impl < ' r , ' t > Index < & ' t str > for Captures < ' r , ' t > {
988
+ impl < ' t > Index < & ' t str > for Captures < ' t > {
966
989
967
990
type Output = str ;
968
991
@@ -979,12 +1002,12 @@ impl<'r, 't> Index<&'t str> for Captures<'r, 't> {
979
1002
/// expression.
980
1003
///
981
1004
/// `'t` is the lifetime of the matched text.
982
- pub struct SubCaptures < ' c , ' r : ' c , ' t : ' c > {
1005
+ pub struct SubCaptures < ' c , ' t : ' c > {
983
1006
idx : usize ,
984
- caps : & ' c Captures < ' r , ' t > ,
1007
+ caps : & ' c Captures < ' t > ,
985
1008
}
986
1009
987
- impl < ' c , ' r , ' t > Iterator for SubCaptures < ' c , ' r , ' t > {
1010
+ impl < ' c , ' t > Iterator for SubCaptures < ' c , ' t > {
988
1011
type Item = Option < & ' t str > ;
989
1012
990
1013
fn next ( & mut self ) -> Option < Option < & ' t str > > {
@@ -1003,41 +1026,42 @@ impl<'c, 'r, 't> Iterator for SubCaptures<'c, 'r, 't> {
1003
1026
/// Positions are byte indices in terms of the original string matched.
1004
1027
///
1005
1028
/// `'t` is the lifetime of the matched text.
1006
- pub struct SubCapturesPos < ' c , ' r : ' c , ' t : ' c > {
1029
+ pub struct SubCapturesPos < ' c > {
1007
1030
idx : usize ,
1008
- caps : & ' c Captures < ' r , ' t > ,
1031
+ locs : & ' c [ Option < usize > ]
1009
1032
}
1010
1033
1011
- impl < ' c , ' r , ' t > Iterator for SubCapturesPos < ' c , ' r , ' t > {
1034
+ impl < ' c > Iterator for SubCapturesPos < ' c > {
1012
1035
type Item = Option < ( usize , usize ) > ;
1013
1036
1014
1037
fn next ( & mut self ) -> Option < Option < ( usize , usize ) > > {
1015
- if self . idx < self . caps . len ( ) {
1016
- self . idx += 1 ;
1017
- Some ( self . caps . pos ( self . idx - 1 ) )
1018
- } else {
1019
- None
1038
+ if self . idx >= self . locs . len ( ) {
1039
+ return None
1020
1040
}
1041
+ let r = match ( self . locs [ self . idx ] , self . locs [ self . idx + 1 ] ) {
1042
+ ( Some ( s) , Some ( e) ) => Some ( ( s, e) ) ,
1043
+ ( None , None ) => None ,
1044
+ _ => unreachable ! ( )
1045
+ } ;
1046
+ self . idx += 2 ;
1047
+ Some ( r)
1021
1048
}
1022
1049
}
1023
1050
1024
1051
/// An Iterator over named capture groups as a tuple with the group
1025
1052
/// name and the value.
1026
1053
///
1027
1054
/// `'t` is the lifetime of the matched text.
1028
- pub struct SubCapturesNamed < ' c , ' r : ' c , ' t : ' c > {
1029
- caps : & ' c Captures < ' r , ' t > ,
1030
- inner : Box < Iterator < Item =( & ' r str , usize ) > + ' r > ,
1055
+ pub struct SubCapturesNamed < ' c , ' t : ' c > {
1056
+ caps : & ' c Captures < ' t > ,
1057
+ names : Box < Iterator < Item =( & ' c str , usize ) > + ' c > ,
1031
1058
}
1032
1059
1033
- impl < ' c , ' r , ' t > Iterator for SubCapturesNamed < ' c , ' r , ' t > {
1034
- type Item = ( & ' r str , Option < & ' t str > ) ;
1060
+ impl < ' c , ' t : ' c > Iterator for SubCapturesNamed < ' c , ' t > {
1061
+ type Item = ( & ' c str , Option < & ' t str > ) ;
1035
1062
1036
- fn next ( & mut self ) -> Option < ( & ' r str , Option < & ' t str > ) > {
1037
- match self . inner . next ( ) {
1038
- Some ( ( name, pos) ) => Some ( ( name, self . caps . at ( pos) ) ) ,
1039
- None => None
1040
- }
1063
+ fn next ( & mut self ) -> Option < ( & ' c str , Option < & ' t str > ) > {
1064
+ self . names . next ( ) . map ( |( name, pos) | ( name, self . caps . at ( pos) ) )
1041
1065
}
1042
1066
}
1043
1067
@@ -1056,9 +1080,9 @@ pub struct FindCaptures<'r, 't> {
1056
1080
}
1057
1081
1058
1082
impl < ' r , ' t > Iterator for FindCaptures < ' r , ' t > {
1059
- type Item = Captures < ' r , ' t > ;
1083
+ type Item = Captures < ' t > ;
1060
1084
1061
- fn next ( & mut self ) -> Option < Captures < ' r , ' t > > {
1085
+ fn next ( & mut self ) -> Option < Captures < ' t > > {
1062
1086
if self . last_end > self . search . len ( ) {
1063
1087
return None
1064
1088
}
@@ -1083,9 +1107,9 @@ impl<'r, 't> Iterator for FindCaptures<'r, 't> {
1083
1107
self . skip_next_empty = true ;
1084
1108
}
1085
1109
Some ( Captures {
1086
- regex : self . re ,
1087
1110
text : self . search ,
1088
- locs : caps
1111
+ locs : caps,
1112
+ named_groups : NamedGroups :: from_regex ( self . re ) ,
1089
1113
} )
1090
1114
}
1091
1115
}
0 commit comments