std: convert each_split_str to an iterator

This commit is contained in:
Huon Wilson
2013-06-10 12:46:35 +10:00
parent ee41ad4168
commit 76fc9be5a1
2 changed files with 119 additions and 122 deletions

View File

@@ -40,7 +40,7 @@ use syntax::visit::{visit_foreign_item, visit_item};
use syntax::visit::{visit_mod, visit_ty, vt}; use syntax::visit::{visit_mod, visit_ty, vt};
use syntax::opt_vec::OptVec; use syntax::opt_vec::OptVec;
use core::str::each_split_str; use core::iterator::IteratorUtil;
use core::str; use core::str;
use core::uint; use core::uint;
use core::vec; use core::vec;
@@ -1737,8 +1737,7 @@ impl Resolver {
entry: %s (%?)", entry: %s (%?)",
path_string, def_like); path_string, def_like);
let mut pieces = ~[]; let mut pieces: ~[&str] = path_string.split_str_iter("::").collect();
for each_split_str(path_string, "::") |s| { pieces.push(s.to_owned()) }
let final_ident_str = pieces.pop(); let final_ident_str = pieces.pop();
let final_ident = self.session.ident_of(final_ident_str); let final_ident = self.session.ident_of(final_ident_str);

View File

@@ -667,6 +667,7 @@ impl<'self> StrCharSplitSeparator for extern "Rust" fn(char) -> bool {
} }
impl<'self, Sep: StrCharSplitSeparator> Iterator<&'self str> for StrCharSplitIterator<'self, Sep> { impl<'self, Sep: StrCharSplitSeparator> Iterator<&'self str> for StrCharSplitIterator<'self, Sep> {
#[inline]
fn next(&mut self) -> Option<&'self str> { fn next(&mut self) -> Option<&'self str> {
if self.finished { return None } if self.finished { return None }
@@ -709,88 +710,69 @@ impl<'self, Sep: StrCharSplitSeparator> Iterator<&'self str> for StrCharSplitIte
} }
} }
// See Issue #1932 for why this is a naive search /// An iterator over the start and end indicies of the matches of a
fn iter_matches<'a,'b>(s: &'a str, sep: &'b str, /// substring within a larger string
f: &fn(uint, uint) -> bool) -> bool { pub struct StrMatchesIndexIterator<'self> {
let (sep_len, l) = (sep.len(), s.len()); priv haystack: &'self str,
assert!(sep_len > 0u); priv needle: &'self str,
let mut (i, match_start, match_i) = (0u, 0u, 0u); priv position: uint,
}
while i < l { /// An iterator over the substrings of a string separated by a given
if s[i] == sep[match_i] { /// search string
if match_i == 0u { match_start = i; } pub struct StrStrSplitIterator<'self> {
match_i += 1u; priv it: StrMatchesIndexIterator<'self>,
// Found a match priv last_end: uint,
if match_i == sep_len { priv finished: bool
if !f(match_start, i + 1u) { return false; } }
match_i = 0u;
impl<'self> Iterator<(uint, uint)> for StrMatchesIndexIterator<'self> {
#[inline]
fn next(&mut self) -> Option<(uint, uint)> {
// See Issue #1932 for why this is a naive search
let (h_len, n_len) = (self.haystack.len(), self.needle.len());
let mut (match_start, match_i) = (0, 0);
while self.position < h_len {
if self.haystack[self.position] == self.needle[match_i] {
if match_i == 0 { match_start = self.position; }
match_i += 1;
self.position += 1;
if match_i == n_len {
// found a match!
return Some((match_start, self.position));
} }
i += 1u;
} else { } else {
// Failed match, backtrack // failed match, backtrack
if match_i > 0u { if match_i > 0 {
match_i = 0u; match_i = 0;
i = match_start + 1u; self.position = match_start;
} else { }
i += 1u; self.position += 1;
} }
} }
None
} }
return true;
} }
fn iter_between_matches<'a,'b>(s: &'a str, impl<'self> Iterator<&'self str> for StrStrSplitIterator<'self> {
sep: &'b str, #[inline]
f: &fn(uint, uint) -> bool) -> bool { fn next(&mut self) -> Option<&'self str> {
let mut last_end = 0u; if self.finished { return None; }
for iter_matches(s, sep) |from, to| {
if !f(last_end, from) { return false; }
last_end = to;
}
return f(last_end, s.len());
}
/** match self.it.next() {
* Splits a string into a vector of the substrings separated by a given string Some((from, to)) => {
* let ret = Some(self.it.haystack.slice(self.last_end, from));
* # Example self.last_end = to;
* ret
* ~~~ {.rust} }
* let mut v = ~[]; None => {
* for each_split_str(".XXX.YYY.", ".") |subs| { v.push(subs); } self.finished = true;
* assert!(v == ["", "XXX", "YYY", ""]); Some(self.it.haystack.slice(self.last_end, self.it.haystack.len()))
* ~~~
*/
pub fn each_split_str<'a,'b>(s: &'a str,
sep: &'b str,
it: &fn(&'a str) -> bool) -> bool {
for iter_between_matches(s, sep) |from, to| {
if !it( unsafe { raw::slice_bytes(s, from, to) } ) { return false; }
} }
return true;
}
/**
* Splits the string `s` based on `sep`, yielding all splits to the iterator
* function provide
*
* # Example
*
* ~~~ {.rust}
* let mut v = ~[];
* for each_split_str(".XXX.YYY.", ".") |subs| { v.push(subs); }
* assert!(v == ["XXX", "YYY"]);
* ~~~
*/
pub fn each_split_str_nonempty<'a,'b>(s: &'a str,
sep: &'b str,
it: &fn(&'a str) -> bool) -> bool {
for iter_between_matches(s, sep) |from, to| {
if to > from {
if !it( unsafe { raw::slice_bytes(s, from, to) } ) { return false; }
} }
} }
return true;
} }
/// Levenshtein Distance between two strings /// Levenshtein Distance between two strings
@@ -929,15 +911,13 @@ pub fn each_split_within<'a>(ss: &'a str,
* The original string with all occurances of `from` replaced with `to` * The original string with all occurances of `from` replaced with `to`
*/ */
pub fn replace(s: &str, from: &str, to: &str) -> ~str { pub fn replace(s: &str, from: &str, to: &str) -> ~str {
let mut (result, first) = (~"", true); let mut (result, last_end) = (~"", 0);
for iter_between_matches(s, from) |start, end| { for s.matches_index_iter(from).advance |(start, end)| {
if first { result.push_str(unsafe{raw::slice_bytes(s, last_end, start)});
first = false; result.push_str(to);
} else { last_end = end;
push_str(&mut result, to);
}
push_str(&mut result, unsafe{raw::slice_bytes(s, start, end)});
} }
result.push_str(unsafe{raw::slice_bytes(s, last_end, s.len())});
result result
} }
@@ -2441,6 +2421,20 @@ pub trait StrSlice<'self> {
fn split_options_iter<Sep: StrCharSplitSeparator>(&self, sep: Sep, fn split_options_iter<Sep: StrCharSplitSeparator>(&self, sep: Sep,
count: uint, allow_trailing_empty: bool) count: uint, allow_trailing_empty: bool)
-> StrCharSplitIterator<'self, Sep>; -> StrCharSplitIterator<'self, Sep>;
/// An iterator over the start and end indices of each match of
/// `sep` within `self`.
fn matches_index_iter(&self, sep: &'self str) -> StrMatchesIndexIterator<'self>;
/**
* An iterator over the substrings of `self` separated by `sep`.
*
* # Example
*
* ~~~ {.rust}
* let v: ~[&str] = ".XXX.YYY.".split_str_iter(".").collect()
* assert_eq!(v, ["", "XXX", "YYY", ""]);
* ~~~
*/
fn split_str_iter(&self, &'self str) -> StrStrSplitIterator<'self>;
/// An iterator over the lines of a string (subsequences separated /// An iterator over the lines of a string (subsequences separated
/// by `\n`). /// by `\n`).
fn line_iter(&self) -> StrCharSplitIterator<'self, char>; fn line_iter(&self) -> StrCharSplitIterator<'self, char>;
@@ -2454,7 +2448,6 @@ pub trait StrSlice<'self> {
fn len(&self) -> uint; fn len(&self) -> uint;
fn char_len(&self) -> uint; fn char_len(&self) -> uint;
fn slice(&self, begin: uint, end: uint) -> &'self str; fn slice(&self, begin: uint, end: uint) -> &'self str;
fn each_split_str<'a>(&self, sep: &'a str, it: &fn(&'self str) -> bool) -> bool;
fn starts_with<'a>(&self, needle: &'a str) -> bool; fn starts_with<'a>(&self, needle: &'a str) -> bool;
fn substr(&self, begin: uint, n: uint) -> &'self str; fn substr(&self, begin: uint, n: uint) -> &'self str;
fn escape_default(&self) -> ~str; fn escape_default(&self) -> ~str;
@@ -2529,6 +2522,21 @@ impl<'self> StrSlice<'self> for &'self str {
only_ascii: only_ascii only_ascii: only_ascii
} }
} }
fn matches_index_iter(&self, sep: &'self str) -> StrMatchesIndexIterator<'self> {
assert!(!sep.is_empty())
StrMatchesIndexIterator {
haystack: *self,
needle: sep,
position: 0
}
}
fn split_str_iter(&self, sep: &'self str) -> StrStrSplitIterator<'self> {
StrStrSplitIterator {
it: self.matches_index_iter(sep),
last_end: 0,
finished: false
}
}
fn line_iter(&self) -> StrCharSplitIterator<'self, char> { fn line_iter(&self) -> StrCharSplitIterator<'self, char> {
self.split_options_iter('\n', self.len(), false) self.split_options_iter('\n', self.len(), false)
@@ -2581,15 +2589,6 @@ impl<'self> StrSlice<'self> for &'self str {
assert!(is_char_boundary(*self, end)); assert!(is_char_boundary(*self, end));
unsafe { raw::slice_bytes(*self, begin, end) } unsafe { raw::slice_bytes(*self, begin, end) }
} }
/**
* Splits a string into a vector of the substrings separated by a given
* string
*/
#[inline]
fn each_split_str<'a>(&self, sep: &'a str, it: &fn(&'self str) -> bool) -> bool {
each_split_str(*self, sep, it)
}
/// Returns true if one string starts with another
#[inline] #[inline]
fn starts_with<'a>(&self, needle: &'a str) -> bool { fn starts_with<'a>(&self, needle: &'a str) -> bool {
starts_with(*self, needle) starts_with(*self, needle)
@@ -2836,30 +2835,6 @@ mod tests {
let _cc3 = pop_char(&mut data); let _cc3 = pop_char(&mut data);
} }
#[test]
fn test_split_str() {
fn t<'a>(s: &str, sep: &'a str, u: &[~str]) {
let mut v = ~[];
for each_split_str(s, sep) |s| { v.push(s.to_owned()) }
assert!(v.iter().zip(u.iter()).all(|(a,b)| a == b));
}
t("--1233345--", "12345", [~"--1233345--"]);
t("abc::hello::there", "::", [~"abc", ~"hello", ~"there"]);
t("::hello::there", "::", [~"", ~"hello", ~"there"]);
t("hello::there::", "::", [~"hello", ~"there", ~""]);
t("::hello::there::", "::", [~"", ~"hello", ~"there", ~""]);
t("ประเทศไทย中华Việt Nam", "中华", [~"ประเทศไทย", ~"Việt Nam"]);
t("zzXXXzzYYYzz", "zz", [~"", ~"XXX", ~"YYY", ~""]);
t("zzXXXzYYYz", "XXX", [~"zz", ~"zYYYz"]);
t(".XXX.YYY.", ".", [~"", ~"XXX", ~"YYY", ~""]);
t("", ".", [~""]);
t("zz", "zz", [~"",~""]);
t("ok", "z", [~"ok"]);
t("zzz", "zz", [~"",~"z"]);
t("zzzzz", "zz", [~"",~"",~"z"]);
}
#[test] #[test]
fn test_split_within() { fn test_split_within() {
fn t(s: &str, i: uint, u: &[~str]) { fn t(s: &str, i: uint, u: &[~str]) {
@@ -3727,4 +3702,27 @@ mod tests {
let lines: ~[&str] = data.line_iter().collect(); let lines: ~[&str] = data.line_iter().collect();
assert_eq!(lines, ~["", "Märy häd ä little lämb", "", "Little lämb"]); assert_eq!(lines, ~["", "Märy häd ä little lämb", "", "Little lämb"]);
} }
#[test]
fn test_split_str_iterator() {
fn t<'a>(s: &str, sep: &'a str, u: ~[&str]) {
let v: ~[&str] = s.split_str_iter(sep).collect();
assert_eq!(v, u);
}
t("--1233345--", "12345", ~["--1233345--"]);
t("abc::hello::there", "::", ~["abc", "hello", "there"]);
t("::hello::there", "::", ~["", "hello", "there"]);
t("hello::there::", "::", ~["hello", "there", ""]);
t("::hello::there::", "::", ~["", "hello", "there", ""]);
t("ประเทศไทย中华Việt Nam", "中华", ~["ประเทศไทย", "Việt Nam"]);
t("zzXXXzzYYYzz", "zz", ~["", "XXX", "YYY", ""]);
t("zzXXXzYYYz", "XXX", ~["zz", "zYYYz"]);
t(".XXX.YYY.", ".", ~["", "XXX", "YYY", ""]);
t("", ".", ~[""]);
t("zz", "zz", ~["",""]);
t("ok", "z", ~["ok"]);
t("zzz", "zz", ~["","z"]);
t("zzzzz", "zz", ~["","","z"]);
}
} }