std: convert character-based str::find_* to methods. Add .slice_{to,from} methods.

This commit is contained in:
Huon Wilson 2013-06-10 13:09:51 +10:00
parent 76fc9be5a1
commit 0cfc08d81e
9 changed files with 158 additions and 405 deletions

View File

@ -417,7 +417,7 @@ fn scan_until_char(haystack: &str, needle: char, idx: &mut uint) -> bool {
if *idx >= haystack.len() {
return false;
}
let opt = str::find_char_from(haystack, needle, *idx);
let opt = haystack.slice_from(*idx).find(needle);
if opt.is_none() {
return false;
}

View File

@ -375,7 +375,7 @@ pub fn check_variants_T<T:Copy>(crate: @ast::crate,
}
pub fn last_part(filename: ~str) -> ~str {
let ix = str::rfind_char(filename, '/').get();
let ix = filename.rfind('/').get();
filename.slice(ix + 1u, filename.len() - 3u).to_owned()
}

View File

@ -841,26 +841,11 @@ fn check_item_non_camel_case_types(cx: &Context, it: @ast::item) {
fn is_camel_case(cx: ty::ctxt, ident: ast::ident) -> bool {
let ident = cx.sess.str_of(ident);
assert!(!ident.is_empty());
let ident = ident_without_trailing_underscores(*ident);
let ident = ident_without_leading_underscores(ident);
let ident = ident.trim_chars(&['_']);
char::is_uppercase(str::char_at(ident, 0)) &&
!ident.contains_char('_')
}
fn ident_without_trailing_underscores<'r>(ident: &'r str) -> &'r str {
match str::rfind(ident, |c| c != '_') {
Some(idx) => ident.slice(0, idx + 1),
None => ident, // all underscores
}
}
fn ident_without_leading_underscores<'r>(ident: &'r str) -> &'r str {
match str::find(ident, |c| c != '_') {
Some(idx) => ident.slice(idx, ident.len()),
None => ident // all underscores
}
}
fn check_case(cx: &Context, ident: ast::ident, span: span) {
if !is_camel_case(cx.tcx, ident) {
cx.span_lint(non_camel_case_types, span,

View File

@ -2681,7 +2681,7 @@ impl Resolver {
match module_prefix_result {
Failed => {
let mpath = self.idents_to_str(module_path);
match str::rfind(self.idents_to_str(module_path), |c| { c == ':' }) {
match self.idents_to_str(module_path).rfind(':') {
Some(idx) => {
self.session.span_err(span, fmt!("unresolved import: could not find `%s` \
in `%s`", str::substr(mpath, idx,

View File

@ -118,19 +118,17 @@ fn first_sentence_(s: &str) -> ~str {
let mut dotcount = 0;
// The index of the character following a single dot. This allows
// Things like [0..1) to appear in the brief description
let idx = do str::find(s) |ch| {
let idx = s.find(|ch: char| {
if ch == '.' {
dotcount += 1;
false
} else if dotcount == 1 {
true
} else {
if dotcount == 1 {
true
} else {
dotcount = 0;
false
}
dotcount = 0;
false
}
};
});
match idx {
Some(idx) if idx > 2u => {
str::to_owned(s.slice(0, idx - 1))

View File

@ -175,7 +175,7 @@ pub fn split_version<'a>(s: &'a str) -> Option<(&'a str, Version)> {
if { let mut i: uint = 0; for str::to_chars(s).each |&c| { if c == '#' { i += 1; } }; i > 1 } {
return None;
}
match str::rfind_char(s, '#') {
match s.rfind('#') {
Some(i) => {
debug!("in %s, i = %?", s, i);
let path = s.slice(0, i);

View File

@ -479,8 +479,8 @@ impl GenericPath for PosixPath {
match self.filename() {
None => None,
Some(ref f) => {
match str::rfind_char(*f, '.') {
Some(p) => Some(f.slice(0, p).to_owned()),
match f.rfind('.') {
Some(p) => Some(f.slice_to(p).to_owned()),
None => Some(copy *f),
}
}
@ -491,8 +491,8 @@ impl GenericPath for PosixPath {
match self.filename() {
None => None,
Some(ref f) => {
match str::rfind_char(*f, '.') {
Some(p) if p < f.len() => Some(f.slice(p, f.len()).to_owned()),
match f.rfind('.') {
Some(p) if p < f.len() => Some(f.slice_from(p).to_owned()),
_ => None,
}
}
@ -693,8 +693,8 @@ impl GenericPath for WindowsPath {
match self.filename() {
None => None,
Some(ref f) => {
match str::rfind_char(*f, '.') {
Some(p) => Some(f.slice(0, p).to_owned()),
match f.rfind('.') {
Some(p) => Some(f.slice_to(p).to_owned()),
None => Some(copy *f),
}
}
@ -705,8 +705,8 @@ impl GenericPath for WindowsPath {
match self.filename() {
None => None,
Some(ref f) => {
match str::rfind_char(*f, '.') {
Some(p) if p < f.len() => Some(f.slice(p, f.len()).to_owned()),
match f.rfind('.') {
Some(p) if p < f.len() => Some(f.slice_from(p).to_owned()),
_ => None,
}
}

View File

@ -21,6 +21,7 @@ use at_vec;
use cast::transmute;
use cast;
use char;
use char::Char;
use clone::Clone;
use cmp::{TotalOrd, Ordering, Less, Equal, Greater};
use container::Container;
@ -510,7 +511,7 @@ pub fn unshift_char(s: &mut ~str, ch: char) {
pub fn trim_left_chars<'a>(s: &'a str, chars_to_trim: &[char]) -> &'a str {
if chars_to_trim.is_empty() { return s; }
match find(s, |c| !chars_to_trim.contains(&c)) {
match s.find(|c| !chars_to_trim.contains(&c)) {
None => "",
Some(first) => unsafe { raw::slice_bytes(s, first, s.len()) }
}
@ -528,7 +529,7 @@ pub fn trim_left_chars<'a>(s: &'a str, chars_to_trim: &[char]) -> &'a str {
pub fn trim_right_chars<'a>(s: &'a str, chars_to_trim: &[char]) -> &'a str {
if chars_to_trim.is_empty() { return s; }
match rfind(s, |c| !chars_to_trim.contains(&c)) {
match s.rfind(|c| !chars_to_trim.contains(&c)) {
None => "",
Some(last) => {
let next = char_range_at(s, last).next;
@ -552,7 +553,7 @@ pub fn trim_chars<'a>(s: &'a str, chars_to_trim: &[char]) -> &'a str {
/// Returns a string with leading whitespace removed
pub fn trim_left<'a>(s: &'a str) -> &'a str {
match find(s, |c| !char::is_whitespace(c)) {
match s.find(|c| !char::is_whitespace(c)) {
None => "",
Some(first) => unsafe { raw::slice_bytes(s, first, s.len()) }
}
@ -560,7 +561,7 @@ pub fn trim_left<'a>(s: &'a str) -> &'a str {
/// Returns a string with trailing whitespace removed
pub fn trim_right<'a>(s: &'a str) -> &'a str {
match rfind(s, |c| !char::is_whitespace(c)) {
match s.rfind(|c| !char::is_whitespace(c)) {
None => "",
Some(last) => {
let next = char_range_at(s, last).next;
@ -621,6 +622,34 @@ pub fn substr<'a>(s: &'a str, begin: uint, n: uint) -> &'a str {
s.slice(begin, begin + count_bytes(s, begin, n))
}
/// Something that can be used to compare against a character
pub trait CharEq {
/// Determine if the splitter should split at the given character
fn matches(&self, char) -> bool;
/// Indicate if this is only concerned about ASCII characters,
/// which can allow for a faster implementation.
fn only_ascii(&self) -> bool;
}
impl CharEq for char {
#[inline(always)]
fn matches(&self, c: char) -> bool { *self == c }
fn only_ascii(&self) -> bool { (*self as uint) < 128 }
}
impl<'self> CharEq for &'self fn(char) -> bool {
#[inline(always)]
fn matches(&self, c: char) -> bool { (*self)(c) }
fn only_ascii(&self) -> bool { false }
}
impl CharEq for extern "Rust" fn(char) -> bool {
#[inline(always)]
fn matches(&self, c: char) -> bool { (*self)(c) }
fn only_ascii(&self) -> bool { false }
}
/// An iterator over the substrings of a string, separated by `sep`.
pub struct StrCharSplitIterator<'self,Sep> {
priv string: &'self str,
@ -639,34 +668,7 @@ pub type WordIterator<'self> =
FilterIterator<'self, &'self str,
StrCharSplitIterator<'self, extern "Rust" fn(char) -> bool>>;
/// A separator for splitting a string character-wise
pub trait StrCharSplitSeparator {
/// Determine if the splitter should split at the given character
fn should_split(&self, char) -> bool;
/// Indicate if the splitter only uses ASCII characters, which
/// allows for a faster implementation.
fn only_ascii(&self) -> bool;
}
impl StrCharSplitSeparator for char {
#[inline(always)]
fn should_split(&self, c: char) -> bool { *self == c }
fn only_ascii(&self) -> bool { (*self as uint) < 128 }
}
impl<'self> StrCharSplitSeparator for &'self fn(char) -> bool {
#[inline(always)]
fn should_split(&self, c: char) -> bool { (*self)(c) }
fn only_ascii(&self) -> bool { false }
}
impl<'self> StrCharSplitSeparator for extern "Rust" fn(char) -> bool {
#[inline(always)]
fn should_split(&self, c: char) -> bool { (*self)(c) }
fn only_ascii(&self) -> bool { false }
}
impl<'self, Sep: StrCharSplitSeparator> Iterator<&'self str> for StrCharSplitIterator<'self, Sep> {
impl<'self, Sep: CharEq> Iterator<&'self str> for StrCharSplitIterator<'self, Sep> {
#[inline]
fn next(&mut self) -> Option<&'self str> {
if self.finished { return None }
@ -680,7 +682,7 @@ impl<'self, Sep: StrCharSplitSeparator> Iterator<&'self str> for StrCharSplitIte
while self.position < l && self.count > 0 {
let byte = self.string[self.position];
if self.sep.should_split(byte as char) {
if self.sep.matches(byte as char) {
let slice = unsafe { raw::slice_bytes(self.string, start, self.position) };
self.position += 1;
self.count -= 1;
@ -692,7 +694,7 @@ impl<'self, Sep: StrCharSplitSeparator> Iterator<&'self str> for StrCharSplitIte
while self.position < l && self.count > 0 {
let CharRange {ch, next} = char_range_at(self.string, self.position);
if self.sep.should_split(ch) {
if self.sep.matches(ch) {
let slice = unsafe { raw::slice_bytes(self.string, start, self.position) };
self.position = next;
self.count -= 1;
@ -1157,318 +1159,6 @@ pub fn map(ss: &str, ff: &fn(char) -> char) -> ~str {
Section: Searching
*/
/**
* Returns the byte index of the first matching character
*
* # Arguments
*
* * `s` - The string to search
* * `c` - The character to search for
*
* # Return value
*
* An `option` containing the byte index of the first matching character
* or `none` if there is no match
*/
pub fn find_char(s: &str, c: char) -> Option<uint> {
find_char_between(s, c, 0u, s.len())
}
/**
* Returns the byte index of the first matching character beginning
* from a given byte offset
*
* # Arguments
*
* * `s` - The string to search
* * `c` - The character to search for
* * `start` - The byte index to begin searching at, inclusive
*
* # Return value
*
* An `option` containing the byte index of the first matching character
* or `none` if there is no match
*
* # Failure
*
* `start` must be less than or equal to `s.len()`. `start` must be the
* index of a character boundary, as defined by `is_char_boundary`.
*/
pub fn find_char_from(s: &str, c: char, start: uint) -> Option<uint> {
find_char_between(s, c, start, s.len())
}
/**
* Returns the byte index of the first matching character within a given range
*
* # Arguments
*
* * `s` - The string to search
* * `c` - The character to search for
* * `start` - The byte index to begin searching at, inclusive
* * `end` - The byte index to end searching at, exclusive
*
* # Return value
*
* An `option` containing the byte index of the first matching character
* or `none` if there is no match
*
* # Failure
*
* `start` must be less than or equal to `end` and `end` must be less than
* or equal to `s.len()`. `start` must be the index of a character boundary,
* as defined by `is_char_boundary`.
*/
pub fn find_char_between(s: &str, c: char, start: uint, end: uint)
-> Option<uint> {
if c < 128u as char {
assert!(start <= end);
assert!(end <= s.len());
let mut i = start;
let b = c as u8;
while i < end {
if s[i] == b { return Some(i); }
i += 1u;
}
return None;
} else {
find_between(s, start, end, |x| x == c)
}
}
/**
* Returns the byte index of the last matching character
*
* # Arguments
*
* * `s` - The string to search
* * `c` - The character to search for
*
* # Return value
*
* An `option` containing the byte index of the last matching character
* or `none` if there is no match
*/
pub fn rfind_char(s: &str, c: char) -> Option<uint> {
rfind_char_between(s, c, s.len(), 0u)
}
/**
* Returns the byte index of the last matching character beginning
* from a given byte offset
*
* # Arguments
*
* * `s` - The string to search
* * `c` - The character to search for
* * `start` - The byte index to begin searching at, exclusive
*
* # Return value
*
* An `option` containing the byte index of the last matching character
* or `none` if there is no match
*
* # Failure
*
* `start` must be less than or equal to `s.len()`. `start` must be
* the index of a character boundary, as defined by `is_char_boundary`.
*/
pub fn rfind_char_from(s: &str, c: char, start: uint) -> Option<uint> {
rfind_char_between(s, c, start, 0u)
}
/**
* Returns the byte index of the last matching character within a given range
*
* # Arguments
*
* * `s` - The string to search
* * `c` - The character to search for
* * `start` - The byte index to begin searching at, exclusive
* * `end` - The byte index to end searching at, inclusive
*
* # Return value
*
* An `option` containing the byte index of the last matching character
* or `none` if there is no match
*
* # Failure
*
* `end` must be less than or equal to `start` and `start` must be less than
* or equal to `s.len()`. `start` must be the index of a character boundary,
* as defined by `is_char_boundary`.
*/
pub fn rfind_char_between(s: &str, c: char, start: uint, end: uint) -> Option<uint> {
if c < 128u as char {
assert!(start >= end);
assert!(start <= s.len());
let mut i = start;
let b = c as u8;
while i > end {
i -= 1u;
if s[i] == b { return Some(i); }
}
return None;
} else {
rfind_between(s, start, end, |x| x == c)
}
}
/**
* Returns the byte index of the first character that satisfies
* the given predicate
*
* # Arguments
*
* * `s` - The string to search
* * `f` - The predicate to satisfy
*
* # Return value
*
* An `option` containing the byte index of the first matching character
* or `none` if there is no match
*/
pub fn find(s: &str, f: &fn(char) -> bool) -> Option<uint> {
find_between(s, 0u, s.len(), f)
}
/**
* Returns the byte index of the first character that satisfies
* the given predicate, beginning from a given byte offset
*
* # Arguments
*
* * `s` - The string to search
* * `start` - The byte index to begin searching at, inclusive
* * `f` - The predicate to satisfy
*
* # Return value
*
* An `option` containing the byte index of the first matching charactor
* or `none` if there is no match
*
* # Failure
*
* `start` must be less than or equal to `s.len()`. `start` must be the
* index of a character boundary, as defined by `is_char_boundary`.
*/
pub fn find_from(s: &str, start: uint, f: &fn(char)
-> bool) -> Option<uint> {
find_between(s, start, s.len(), f)
}
/**
* Returns the byte index of the first character that satisfies
* the given predicate, within a given range
*
* # Arguments
*
* * `s` - The string to search
* * `start` - The byte index to begin searching at, inclusive
* * `end` - The byte index to end searching at, exclusive
* * `f` - The predicate to satisfy
*
* # Return value
*
* An `option` containing the byte index of the first matching character
* or `none` if there is no match
*
* # Failure
*
* `start` must be less than or equal to `end` and `end` must be less than
* or equal to `s.len()`. `start` must be the index of a character
* boundary, as defined by `is_char_boundary`.
*/
pub fn find_between(s: &str, start: uint, end: uint, f: &fn(char) -> bool) -> Option<uint> {
assert!(start <= end);
assert!(end <= s.len());
assert!(is_char_boundary(s, start));
let mut i = start;
while i < end {
let CharRange {ch, next} = char_range_at(s, i);
if f(ch) { return Some(i); }
i = next;
}
return None;
}
/**
* Returns the byte index of the last character that satisfies
* the given predicate
*
* # Arguments
*
* * `s` - The string to search
* * `f` - The predicate to satisfy
*
* # Return value
*
* An option containing the byte index of the last matching character
* or `none` if there is no match
*/
pub fn rfind(s: &str, f: &fn(char) -> bool) -> Option<uint> {
rfind_between(s, s.len(), 0u, f)
}
/**
* Returns the byte index of the last character that satisfies
* the given predicate, beginning from a given byte offset
*
* # Arguments
*
* * `s` - The string to search
* * `start` - The byte index to begin searching at, exclusive
* * `f` - The predicate to satisfy
*
* # Return value
*
* An `option` containing the byte index of the last matching character
* or `none` if there is no match
*
* # Failure
*
* `start` must be less than or equal to `s.len()', `start` must be the
* index of a character boundary, as defined by `is_char_boundary`
*/
pub fn rfind_from(s: &str, start: uint, f: &fn(char) -> bool) -> Option<uint> {
rfind_between(s, start, 0u, f)
}
/**
* Returns the byte index of the last character that satisfies
* the given predicate, within a given range
*
* # Arguments
*
* * `s` - The string to search
* * `start` - The byte index to begin searching at, exclusive
* * `end` - The byte index to end searching at, inclusive
* * `f` - The predicate to satisfy
*
* # Return value
*
* An `option` containing the byte index of the last matching character
* or `none` if there is no match
*
* # Failure
*
* `end` must be less than or equal to `start` and `start` must be less
* than or equal to `s.len()`. `start` must be the index of a character
* boundary, as defined by `is_char_boundary`
*/
pub fn rfind_between(s: &str, start: uint, end: uint, f: &fn(char) -> bool) -> Option<uint> {
assert!(start >= end);
assert!(start <= s.len());
assert!(is_char_boundary(s, start));
let mut i = start;
while i > end {
let CharRange {ch, next: prev} = char_range_at_reverse(s, i);
if f(ch) { return Some(prev); }
i = prev;
}
return None;
}
// Utility used by various searching functions
fn match_at<'a,'b>(haystack: &'a str, needle: &'b str, at: uint) -> bool {
let mut i = at;
@ -1580,7 +1270,7 @@ pub fn contains<'a,'b>(haystack: &'a str, needle: &'b str) -> bool {
* * needle - The char to look for
*/
pub fn contains_char(haystack: &str, needle: char) -> bool {
find_char(haystack, needle).is_some()
haystack.find(needle).is_some()
}
/**
@ -2415,11 +2105,9 @@ pub trait StrSlice<'self> {
fn rev_iter(&self) -> StrCharRevIterator<'self>;
fn bytes_iter(&self) -> StrBytesIterator<'self>;
fn bytes_rev_iter(&self) -> StrBytesRevIterator<'self>;
fn split_iter<Sep: StrCharSplitSeparator>(&self, sep: Sep) -> StrCharSplitIterator<'self, Sep>;
fn splitn_iter<Sep: StrCharSplitSeparator>(&self, sep: Sep, count: uint)
-> StrCharSplitIterator<'self, Sep>;
fn split_options_iter<Sep: StrCharSplitSeparator>(&self, sep: Sep,
count: uint, allow_trailing_empty: bool)
fn split_iter<Sep: CharEq>(&self, sep: Sep) -> StrCharSplitIterator<'self, Sep>;
fn splitn_iter<Sep: CharEq>(&self, sep: Sep, count: uint) -> StrCharSplitIterator<'self, Sep>;
fn split_options_iter<Sep: CharEq>(&self, sep: Sep, count: uint, allow_trailing_empty: bool)
-> StrCharSplitIterator<'self, Sep>;
/// An iterator over the start and end indices of each match of
/// `sep` within `self`.
@ -2448,6 +2136,8 @@ pub trait StrSlice<'self> {
fn len(&self) -> uint;
fn char_len(&self) -> uint;
fn slice(&self, begin: uint, end: uint) -> &'self str;
fn slice_from(&self, begin: uint) -> &'self str;
fn slice_to(&self, end: uint) -> &'self str;
fn starts_with<'a>(&self, needle: &'a str) -> bool;
fn substr(&self, begin: uint, n: uint) -> &'self str;
fn escape_default(&self) -> ~str;
@ -2463,6 +2153,9 @@ pub trait StrSlice<'self> {
fn char_at(&self, i: uint) -> char;
fn char_at_reverse(&self, i: uint) -> char;
fn to_bytes(&self) -> ~[u8];
fn find<C: CharEq>(&self, search: C) -> Option<uint>;
fn rfind<C: CharEq>(&self, search: C) -> Option<uint>;
}
/// Extension methods for strings
@ -2500,16 +2193,14 @@ impl<'self> StrSlice<'self> for &'self str {
StrBytesRevIterator { it: as_bytes_slice(*self).rev_iter() }
}
fn split_iter<Sep: StrCharSplitSeparator>(&self, sep: Sep) -> StrCharSplitIterator<'self, Sep> {
fn split_iter<Sep: CharEq>(&self, sep: Sep) -> StrCharSplitIterator<'self, Sep> {
self.split_options_iter(sep, self.len(), true)
}
fn splitn_iter<Sep: StrCharSplitSeparator>(&self, sep: Sep, count: uint)
-> StrCharSplitIterator<'self, Sep> {
fn splitn_iter<Sep: CharEq>(&self, sep: Sep, count: uint) -> StrCharSplitIterator<'self, Sep> {
self.split_options_iter(sep, count, true)
}
fn split_options_iter<Sep: StrCharSplitSeparator>(&self, sep: Sep,
count: uint, allow_trailing_empty: bool)
fn split_options_iter<Sep: CharEq>(&self, sep: Sep, count: uint, allow_trailing_empty: bool)
-> StrCharSplitIterator<'self, Sep> {
let only_ascii = sep.only_ascii();
StrCharSplitIterator {
@ -2590,6 +2281,14 @@ impl<'self> StrSlice<'self> for &'self str {
unsafe { raw::slice_bytes(*self, begin, end) }
}
#[inline]
fn slice_from(&self, begin: uint) -> &'self str {
self.slice(begin, self.len())
}
#[inline]
fn slice_to(&self, end: uint) -> &'self str {
self.slice(0, end)
}
#[inline]
fn starts_with<'a>(&self, needle: &'a str) -> bool {
starts_with(*self, needle)
}
@ -2654,6 +2353,54 @@ impl<'self> StrSlice<'self> for &'self str {
}
fn to_bytes(&self) -> ~[u8] { to_bytes(*self) }
/**
* Returns the byte index of the first character of `self` that matches `search`
*
* # Return value
*
* `Some` containing the byte index of the last matching character
* or `None` if there is no match
*/
fn find<C: CharEq>(&self, search: C) -> Option<uint> {
if search.only_ascii() {
for self.bytes_iter().enumerate().advance |(i, b)| {
if search.matches(b as char) { return Some(i) }
}
} else {
let mut index = 0;
for self.iter().advance |c| {
if search.matches(c) { return Some(index); }
index += c.len_utf8_bytes();
}
}
None
}
/**
* Returns the byte index of the last character of `self` that matches `search`
*
* # Return value
*
* `Some` containing the byte index of the last matching character
* or `None` if there is no match
*/
fn rfind<C: CharEq>(&self, search: C) -> Option<uint> {
let mut index = self.len();
if search.only_ascii() {
for self.bytes_rev_iter().advance |b| {
index -= 1;
if search.matches(b as char) { return Some(index); }
}
} else {
for self.rev_iter().advance |c| {
index -= c.len_utf8_bytes();
if search.matches(c) { return Some(index); }
}
}
None
}
}
#[allow(missing_doc)]
@ -2803,12 +2550,23 @@ mod tests {
}
#[test]
fn test_rfind_char() {
assert_eq!(rfind_char("hello", 'l'), Some(3u));
assert_eq!(rfind_char("hello", 'o'), Some(4u));
assert_eq!(rfind_char("hello", 'h'), Some(0u));
assert!(rfind_char("hello", 'z').is_none());
assert_eq!(rfind_char("ประเทศไทย中华Việt Nam", '华'), Some(30u));
fn test_find() {
assert_eq!("hello".find('l'), Some(2u));
assert_eq!("hello".find(|c:char| c == 'o'), Some(4u));
assert!("hello".find('x').is_none());
assert!("hello".find(|c:char| c == 'x').is_none());
assert_eq!("ประเทศไทย中华Việt Nam".find('华'), Some(30u));
assert_eq!("ประเทศไทย中华Việt Nam".find(|c: char| c == '华'), Some(30u));
}
#[test]
fn test_rfind() {
assert_eq!("hello".rfind('l'), Some(3u));
assert_eq!("hello".rfind(|c:char| c == 'o'), Some(4u));
assert!("hello".rfind('x').is_none());
assert!("hello".rfind(|c:char| c == 'x').is_none());
assert_eq!("ประเทศไทย中华Việt Nam".rfind('华'), Some(30u));
assert_eq!("ประเทศไทย中华Việt Nam".rfind(|c: char| c == '华'), Some(30u));
}
#[test]
@ -3122,6 +2880,19 @@ mod tests {
"中华Việt Nam".slice(0u, 2u);
}
#[test]
fn test_slice_from() {
assert_eq!("abcd".slice_from(0), "abcd");
assert_eq!("abcd".slice_from(2), "cd");
assert_eq!("abcd".slice_from(4), "");
}
#[test]
fn test_slice_to() {
assert_eq!("abcd".slice_to(0), "");
assert_eq!("abcd".slice_to(2), "ab");
assert_eq!("abcd".slice_to(4), "abcd");
}
#[test]
fn test_trim_left_chars() {
assert!(trim_left_chars(" *** foo *** ", []) == " *** foo *** ");

View File

@ -24,7 +24,6 @@ source code snippets, etc.
use core::prelude::*;
use core::cmp;
use core::str;
use core::to_bytes;
use core::uint;
use extra::serialize::{Encodable, Decodable, Encoder, Decoder};
@ -288,11 +287,11 @@ impl FileMap {
pub fn get_line(&self, line: int) -> ~str {
let begin: BytePos = self.lines[line] - self.start_pos;
let begin = begin.to_uint();
let end = match str::find_char_from(*self.src, '\n', begin) {
Some(e) => e,
None => self.src.len()
};
self.src.slice(begin, end).to_owned()
let slice = self.src.slice_from(begin);
match slice.find('\n') {
Some(e) => slice.slice_to(e).to_owned(),
None => slice.to_owned()
}
}
pub fn record_multibyte_char(&self, pos: BytePos, bytes: uint) {