@@ -10,9 +10,8 @@ use crate::iter::{Map, Cloned, FusedIterator, TrustedLen, TrustedRandomAccess, F
1010use crate :: iter:: { Flatten , FlatMap , Chain } ;
1111use crate :: slice:: { self , SliceIndex , Split as SliceSplit } ;
1212use crate :: mem;
13- use crate :: needle:: {
14- ext, Needle , Searcher , ReverseSearcher , Consumer , ReverseConsumer , DoubleEndedConsumer ,
15- } ;
13+ use crate :: needle:: { ext, Needle , Searcher , ReverseSearcher , Consumer , ReverseConsumer , DoubleEndedConsumer } ;
14+ use crate :: ops:: Range ;
1615
1716#[ unstable( feature = "str_internals" , issue = "0" ) ]
1817mod needles;
@@ -2549,6 +2548,105 @@ impl str {
25492548 ext:: rfind ( self , pat)
25502549 }
25512550
2551+ /// Returns the byte range of the first substring of this string slice that
2552+ /// the pattern can be found.
2553+ ///
2554+ /// Returns [`None`] if the pattern doesn't match.
2555+ ///
2556+ /// The pattern can be a `&str`, [`char`], or a closure that determines if
2557+ /// a substring matches.
2558+ ///
2559+ /// [`None`]: option/enum.Option.html#variant.None
2560+ ///
2561+ /// # Examples
2562+ ///
2563+ /// Simple patterns:
2564+ ///
2565+ /// ```
2566+ /// let s = "Löwe 老虎 Léopard";
2567+ ///
2568+ /// assert_eq!(s.find_range('L'), Some(0..1));
2569+ /// assert_eq!(s.find_range('é'), Some(14..16));
2570+ /// assert_eq!(s.find_range("Léopard"), Some(13..21));
2571+ /// ```
2572+ ///
2573+ /// More complex patterns using point-free style and closures:
2574+ ///
2575+ /// ```
2576+ /// let s = "Löwe 老虎 Léopard";
2577+ ///
2578+ /// assert_eq!(s.find(char::is_whitespace), Some(5..6));
2579+ /// assert_eq!(s.find(char::is_lowercase), Some(1..2));
2580+ /// assert_eq!(s.find(|c: char| c.is_whitespace() || c.is_lowercase()), Some(1..2));
2581+ /// assert_eq!(s.find(|c: char| (c < 'o') && (c > 'a')), Some(4..5));
2582+ /// ```
2583+ ///
2584+ /// Not finding the pattern:
2585+ ///
2586+ /// ```
2587+ /// let s = "Löwe 老虎 Léopard";
2588+ /// let x: &[_] = &['1', '2'];
2589+ ///
2590+ /// assert_eq!(s.find(x), None);
2591+ /// ```
2592+ #[ unstable( feature = "str_find_range" , issue = "56345" ) ]
2593+ #[ inline]
2594+ pub fn find_range < ' a , P : Needle < & ' a str > > ( & ' a self , pat : P ) -> Option < Range < usize > >
2595+ where
2596+ P :: Searcher : Searcher < str > , // FIXME: RFC 2089
2597+ P :: Consumer : Consumer < str > , // FIXME: RFC 2089
2598+ {
2599+ ext:: find_range ( self , pat)
2600+ }
2601+
2602+ /// Returns the byte range of the last substring of this string slice that
2603+ /// the pattern can be found.
2604+ ///
2605+ /// Returns [`None`] if the pattern doesn't match.
2606+ ///
2607+ /// The pattern can be a `&str`, [`char`], or a closure that determines if
2608+ /// a substring matches.
2609+ ///
2610+ /// [`None`]: option/enum.Option.html#variant.None
2611+ ///
2612+ /// # Examples
2613+ ///
2614+ /// Simple patterns:
2615+ ///
2616+ /// ```
2617+ /// let s = "Löwe 老虎 Léopard";
2618+ ///
2619+ /// assert_eq!(s.rfind_range('L'), Some(13..14));
2620+ /// assert_eq!(s.rfind_range('é'), Some(14..16));
2621+ /// ```
2622+ ///
2623+ /// More complex patterns with closures:
2624+ ///
2625+ /// ```
2626+ /// let s = "Löwe 老虎 Léopard";
2627+ ///
2628+ /// assert_eq!(s.rfind_range(char::is_whitespace), Some(12..13));
2629+ /// assert_eq!(s.rfind_range(char::is_lowercase), Some(20..21));
2630+ /// ```
2631+ ///
2632+ /// Not finding the pattern:
2633+ ///
2634+ /// ```
2635+ /// let s = "Löwe 老虎 Léopard";
2636+ /// let x: &[_] = &['1', '2'];
2637+ ///
2638+ /// assert_eq!(s.rfind_range(x), None);
2639+ /// ```
2640+ #[ unstable( feature = "str_find_range" , issue = "56345" ) ]
2641+ #[ inline]
2642+ pub fn rfind_range < ' a , P : Needle < & ' a str > > ( & ' a self , pat : P ) -> Option < Range < usize > >
2643+ where
2644+ P :: Searcher : ReverseSearcher < str > ,
2645+ P :: Consumer : Consumer < str > , // FIXME: RFC 2089
2646+ {
2647+ ext:: rfind_range ( self , pat)
2648+ }
2649+
25522650 /// An iterator over substrings of this string slice, separated by
25532651 /// characters matched by a pattern.
25542652 ///
@@ -3083,6 +3181,99 @@ impl str {
30833181 ext:: rmatch_indices ( self , pat)
30843182 }
30853183
3184+ /// An iterator over the disjoint matches of a pattern within this string
3185+ /// slice as well as the range that the match covers.
3186+ ///
3187+ /// For matches of `pat` within `self` that overlap, only the ranges
3188+ /// corresponding to the first match are returned.
3189+ ///
3190+ /// The pattern can be a `&str`, [`char`], or a closure that determines
3191+ /// if a substring matches.
3192+ ///
3193+ /// # Iterator behavior
3194+ ///
3195+ /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern
3196+ /// allows a reverse search and forward/reverse search yields the same
3197+ /// elements. This is true for, eg, [`char`] but not for `&str`.
3198+ ///
3199+ /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
3200+ ///
3201+ /// If the pattern allows a reverse search but its results might differ
3202+ /// from a forward search, the [`rmatch_ranges`] method can be used.
3203+ ///
3204+ /// [`rmatch_ranges`]: #method.rmatch_ranges
3205+ ///
3206+ /// # Examples
3207+ ///
3208+ /// Basic usage:
3209+ ///
3210+ /// ```
3211+ /// let v: Vec<_> = "abcXXXabcYYYabc".match_ranges("abc").collect();
3212+ /// assert_eq!(v, [(0..3, "abc"), (6..9, "abc"), (12..15, "abc")]);
3213+ ///
3214+ /// let v: Vec<_> = "1abcabc2".match_ranges("abc").collect();
3215+ /// assert_eq!(v, [(1..4, "abc"), (4..7, "abc")]);
3216+ ///
3217+ /// let v: Vec<_> = "ababa".match_ranges("aba").collect();
3218+ /// assert_eq!(v, [(0..3, "aba")]); // only the first `aba`
3219+ /// ```
3220+ #[ unstable( feature = "str_find_range" , issue = "56345" ) ]
3221+ #[ inline]
3222+ pub fn match_ranges < ' a , P > ( & ' a self , pat : P ) -> ext:: MatchRanges < & ' a str , P :: Searcher >
3223+ where
3224+ P : Needle < & ' a str > ,
3225+ P :: Searcher : Searcher < str > , // FIXME: RFC 2089
3226+ P :: Consumer : Consumer < str > , // FIXME: RFC 2089
3227+ {
3228+ ext:: match_ranges ( self , pat)
3229+ }
3230+
3231+ /// An iterator over the disjoint matches of a pattern within `self`,
3232+ /// yielded in reverse order along with the range of the match.
3233+ ///
3234+ /// For matches of `pat` within `self` that overlap, only the ranges
3235+ /// corresponding to the last match are returned.
3236+ ///
3237+ /// The pattern can be a `&str`, [`char`], or a closure that determines if a
3238+ /// substring matches.
3239+ ///
3240+ /// # Iterator behavior
3241+ ///
3242+ /// The returned iterator requires that the pattern supports a reverse
3243+ /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse
3244+ /// search yields the same elements.
3245+ ///
3246+ /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
3247+ ///
3248+ /// For iterating from the front, the [`match_ranges`] method can be used.
3249+ ///
3250+ /// [`match_ranges`]: #method.match_ranges
3251+ ///
3252+ /// # Examples
3253+ ///
3254+ /// Basic usage:
3255+ ///
3256+ /// ```
3257+ /// let v: Vec<_> = "abcXXXabcYYYabc".rmatch_ranges("abc").collect();
3258+ /// assert_eq!(v, [(12..15, "abc"), (6..9, "abc"), (0..3, "abc")]);
3259+ ///
3260+ /// let v: Vec<_> = "1abcabc2".rmatch_ranges("abc").collect();
3261+ /// assert_eq!(v, [(4..7, "abc"), (1..4, "abc")]);
3262+ ///
3263+ /// let v: Vec<_> = "ababa".rmatch_ranges("aba").collect();
3264+ /// assert_eq!(v, [(2..5, "aba")]); // only the last `aba`
3265+ /// ```
3266+ #[ unstable( feature = "str_find_range" , issue = "56345" ) ]
3267+ #[ inline]
3268+ pub fn rmatch_ranges < ' a , P > ( & ' a self , pat : P ) -> ext:: RMatchRanges < & ' a str , P :: Searcher >
3269+ where
3270+ P : Needle < & ' a str > ,
3271+ P :: Searcher : ReverseSearcher < str > ,
3272+ P :: Consumer : Consumer < str > , // FIXME: RFC 2089
3273+ {
3274+ ext:: rmatch_ranges ( self , pat)
3275+ }
3276+
30863277 /// Returns a string slice with leading and trailing whitespace removed.
30873278 ///
30883279 /// 'Whitespace' is defined according to the terms of the Unicode Derived
0 commit comments