Skip to content

Commit

Permalink
std: Update MatchIndices to return a subslice
Browse files Browse the repository at this point in the history
This commit updates the `MatchIndices` and `RMatchIndices` iterators to follow
the same pattern as the `chars` and `char_indices` iterators. The `matches`
iterator currently yield `&str` elements, so the `MatchIndices` iterator now
yields the index of the match as well as the `&str` that matched (instead of
start/end indexes).

cc rust-lang#27743
  • Loading branch information
alexcrichton committed Sep 25, 2015
1 parent 8fe79bd commit d5f2d3b
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 52 deletions.
72 changes: 30 additions & 42 deletions src/libcollections/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1157,25 +1157,21 @@ impl str {
core_str::StrExt::rmatches(self, pat)
}

/// An iterator over the start and end indices of the disjoint matches
/// of a pattern within `self`.
/// An iterator over the disjoint matches of a pattern within `self` as well
/// as the index that the match starts at.
///
/// For matches of `pat` within `self` that overlap, only the indices
/// corresponding to the first
/// match are returned.
/// corresponding to the first match are returned.
///
/// The pattern can be a simple `&str`, `char`, or a closure that
/// determines if a character matches.
/// Additional libraries might provide more complex patterns like
/// regular expressions.
/// The pattern can be a simple `&str`, `char`, or a closure that determines
/// if a character matches. Additional libraries might provide more complex
/// patterns like regular expressions.
///
/// # Iterator behavior
///
/// The returned iterator will be double ended if the pattern allows a
/// reverse search
/// and forward/reverse search yields the same elements. This is true for,
/// eg, `char` but not
/// for `&str`.
/// reverse search and forward/reverse search yields the same elements. This
/// is true for, eg, `char` but not for `&str`.
///
/// If the pattern allows a reverse search but its results might differ
/// from a forward search, `rmatch_indices()` can be used.
Expand All @@ -1185,42 +1181,36 @@ impl str {
/// ```
/// #![feature(str_match_indices)]
///
/// let v: Vec<(usize, usize)> = "abcXXXabcYYYabc".match_indices("abc").collect();
/// assert_eq!(v, [(0, 3), (6, 9), (12, 15)]);
/// let v: Vec<_> = "abcXXXabcYYYabc".match_indices("abc").collect();
/// assert_eq!(v, [(0, "abc"), (6, "abc"), (12, "abc")]);
///
/// let v: Vec<(usize, usize)> = "1abcabc2".match_indices("abc").collect();
/// assert_eq!(v, [(1, 4), (4, 7)]);
/// let v: Vec<_> = "1abcabc2".match_indices("abc").collect();
/// assert_eq!(v, [(1, "abc"), (4, "abc")]);
///
/// let v: Vec<(usize, usize)> = "ababa".match_indices("aba").collect();
/// assert_eq!(v, [(0, 3)]); // only the first `aba`
/// let v: Vec<_> = "ababa".match_indices("aba").collect();
/// assert_eq!(v, [(0, "aba")]); // only the first `aba`
/// ```
#[unstable(feature = "str_match_indices",
reason = "might have its iterator type changed",
issue = "27743")]
// NB: Right now MatchIndices yields `(usize, usize)`, but it would
// be more consistent with `matches` and `char_indices` to return `(usize, &str)`
pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> {
core_str::StrExt::match_indices(self, pat)
}

/// An iterator over the start and end indices of the disjoint matches of
/// a pattern within
/// `self`, yielded in reverse order.
/// An iterator over the disjoint matches of a pattern within `self`,
/// yielded in reverse order along with the index of the match.
///
/// For matches of `pat` within `self` that overlap, only the indices
/// corresponding to the last
/// match are returned.
/// corresponding to the last match are returned.
///
/// The pattern can be a simple `&str`, `char`, or a closure that
/// determines if a character matches.
/// Additional libraries might provide more complex patterns like
/// regular expressions.
/// The pattern can be a simple `&str`, `char`, or a closure that determines
/// if a character matches. Additional libraries might provide more complex
/// patterns like regular expressions.
///
/// # Iterator behavior
///
/// The returned iterator requires that the pattern supports a
/// reverse search,
/// and it will be double ended if a forward/reverse search yields
/// The returned iterator requires that the pattern supports a reverse
/// search, and it will be double ended if a forward/reverse search yields
/// the same elements.
///
/// For iterating from the front, `match_indices()` can be used.
Expand All @@ -1230,20 +1220,18 @@ impl str {
/// ```
/// #![feature(str_match_indices)]
///
/// let v: Vec<(usize, usize)> = "abcXXXabcYYYabc".rmatch_indices("abc").collect();
/// assert_eq!(v, [(12, 15), (6, 9), (0, 3)]);
/// let v: Vec<_> = "abcXXXabcYYYabc".rmatch_indices("abc").collect();
/// assert_eq!(v, [(12, "abc"), (6, "abc"), (0, "abc")]);
///
/// let v: Vec<(usize, usize)> = "1abcabc2".rmatch_indices("abc").collect();
/// assert_eq!(v, [(4, 7), (1, 4)]);
/// let v: Vec<_> = "1abcabc2".rmatch_indices("abc").collect();
/// assert_eq!(v, [(4, "abc"), (1, "abc")]);
///
/// let v: Vec<(usize, usize)> = "ababa".rmatch_indices("aba").collect();
/// assert_eq!(v, [(2, 5)]); // only the last `aba`
/// let v: Vec<_> = "ababa".rmatch_indices("aba").collect();
/// assert_eq!(v, [(2, "aba")]); // only the last `aba`
/// ```
#[unstable(feature = "str_match_indices",
reason = "might have its iterator type changed",
issue = "27743")]
// NB: Right now RMatchIndices yields `(usize, usize)`, but it would
// be more consistent with `rmatches` and `char_indices` to return `(usize, &str)`
pub fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P>
where P::Searcher: ReverseSearcher<'a>
{
Expand Down Expand Up @@ -1416,10 +1404,10 @@ impl str {
pub fn replace(&self, from: &str, to: &str) -> String {
let mut result = String::new();
let mut last_end = 0;
for (start, end) in self.match_indices(from) {
for (start, part) in self.match_indices(from) {
result.push_str(unsafe { self.slice_unchecked(last_end, start) });
result.push_str(to);
last_end = end;
last_end = start + part.len();
}
result.push_str(unsafe { self.slice_unchecked(last_end, self.len()) });
result
Expand Down
4 changes: 2 additions & 2 deletions src/libcollectionstest/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1047,7 +1047,7 @@ fn test_pattern_deref_forward() {
fn test_empty_match_indices() {
let data = "aä中!";
let vec: Vec<_> = data.match_indices("").collect();
assert_eq!(vec, [(0, 0), (1, 1), (3, 3), (6, 6), (7, 7)]);
assert_eq!(vec, [(0, ""), (1, ""), (3, ""), (6, ""), (7, "")]);
}

#[test]
Expand Down Expand Up @@ -1477,7 +1477,7 @@ generate_iterator_test! {

generate_iterator_test! {
double_ended_match_indices {
("a1b2c3", char::is_numeric) -> [(1, 2), (3, 4), (5, 6)];
("a1b2c3", char::is_numeric) -> [(1, "1"), (3, "2"), (5, "3")];
}
with str::match_indices, str::rmatch_indices;
}
Expand Down
14 changes: 9 additions & 5 deletions src/libcore/str/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -729,15 +729,19 @@ struct MatchIndicesInternal<'a, P: Pattern<'a>>(P::Searcher);

impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> {
#[inline]
fn next(&mut self) -> Option<(usize, usize)> {
self.0.next_match()
fn next(&mut self) -> Option<(usize, &'a str)> {
self.0.next_match().map(|(start, end)| unsafe {
(start, self.0.haystack().slice_unchecked(start, end))
})
}

#[inline]
fn next_back(&mut self) -> Option<(usize, usize)>
fn next_back(&mut self) -> Option<(usize, &'a str)>
where P::Searcher: ReverseSearcher<'a>
{
self.0.next_match_back()
self.0.next_match_back().map(|(start, end)| unsafe {
(start, self.0.haystack().slice_unchecked(start, end))
})
}
}

Expand All @@ -753,7 +757,7 @@ generate_pattern_iterators! {
reason = "type may be removed or have its iterator impl changed",
issue = "27743")]
internal:
MatchIndicesInternal yielding ((usize, usize));
MatchIndicesInternal yielding ((usize, &'a str));
delegate double ended;
}

Expand Down
4 changes: 2 additions & 2 deletions src/librustc/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,10 +331,10 @@ fn split_msg_into_multilines(msg: &str) -> Option<String> {
let first = msg.match_indices("expected").filter(|s| {
s.0 > 0 && (msg.char_at_reverse(s.0) == ' ' ||
msg.char_at_reverse(s.0) == '(')
}).map(|(a, b)| (a - 1, b));
}).map(|(a, b)| (a - 1, a + b.len()));
let second = msg.match_indices("found").filter(|s| {
msg.char_at_reverse(s.0) == ' '
}).map(|(a, b)| (a - 1, b));
}).map(|(a, b)| (a - 1, a + b.len()));

let mut new_msg = String::new();
let mut head = 0;
Expand Down
2 changes: 1 addition & 1 deletion src/test/run-pass/issue-14919.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,5 @@ fn match_indices<'a, M, T: IntoMatcher<'a, M>>(s: &'a str, from: T) -> MatchIndi
fn main() {
let s = "abcbdef";
match_indices(s, |c: char| c == 'b')
.collect::<Vec<(usize, usize)>>();
.collect::<Vec<_>>();
}

0 comments on commit d5f2d3b

Please sign in to comment.