Skip to content

Commit aecf8c2

Browse files
committed
Add trim_start, trim_end, trim_start_matches and trim_end_matches
1 parent 03da14b commit aecf8c2

File tree

3 files changed

+218
-13
lines changed

3 files changed

+218
-13
lines changed

src/liballoc/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#![feature(unboxed_closures)]
2626
#![feature(exact_chunks)]
2727
#![feature(repeat_generic_slice)]
28+
#![feature(trim_direction)]
2829

2930
extern crate alloc_system;
3031
extern crate core;

src/liballoc/tests/str.rs

+58
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,36 @@ fn test_is_char_boundary() {
726726
}
727727
}
728728

729+
#[test]
730+
fn test_trim_start_matches() {
731+
let v: &[char] = &[];
732+
assert_eq!(" *** foo *** ".trim_start_matches(v), " *** foo *** ");
733+
let chars: &[char] = &['*', ' '];
734+
assert_eq!(" *** foo *** ".trim_start_matches(chars), "foo *** ");
735+
assert_eq!(" *** *** ".trim_start_matches(chars), "");
736+
assert_eq!("foo *** ".trim_start_matches(chars), "foo *** ");
737+
738+
assert_eq!("11foo1bar11".trim_start_matches('1'), "foo1bar11");
739+
let chars: &[char] = &['1', '2'];
740+
assert_eq!("12foo1bar12".trim_start_matches(chars), "foo1bar12");
741+
assert_eq!("123foo1bar123".trim_start_matches(|c: char| c.is_numeric()), "foo1bar123");
742+
}
743+
744+
#[test]
745+
fn test_trim_end_matches() {
746+
let v: &[char] = &[];
747+
assert_eq!(" *** foo *** ".trim_end_matches(v), " *** foo *** ");
748+
let chars: &[char] = &['*', ' '];
749+
assert_eq!(" *** foo *** ".trim_end_matches(chars), " *** foo");
750+
assert_eq!(" *** *** ".trim_end_matches(chars), "");
751+
assert_eq!(" *** foo".trim_end_matches(chars), " *** foo");
752+
753+
assert_eq!("11foo1bar11".trim_end_matches('1'), "11foo1bar");
754+
let chars: &[char] = &['1', '2'];
755+
assert_eq!("12foo1bar12".trim_end_matches(chars), "12foo1bar");
756+
assert_eq!("123foo1bar123".trim_end_matches(|c: char| c.is_numeric()), "123foo1bar");
757+
}
758+
729759
#[test]
730760
fn test_trim_left_matches() {
731761
let v: &[char] = &[];
@@ -771,6 +801,26 @@ fn test_trim_matches() {
771801
assert_eq!("123foo1bar123".trim_matches(|c: char| c.is_numeric()), "foo1bar");
772802
}
773803

804+
#[test]
805+
fn test_trim_start() {
806+
assert_eq!("".trim_start(), "");
807+
assert_eq!("a".trim_start(), "a");
808+
assert_eq!(" ".trim_start(), "");
809+
assert_eq!(" blah".trim_start(), "blah");
810+
assert_eq!(" \u{3000} wut".trim_start(), "wut");
811+
assert_eq!("hey ".trim_start(), "hey ");
812+
}
813+
814+
#[test]
815+
fn test_trim_end() {
816+
assert_eq!("".trim_end(), "");
817+
assert_eq!("a".trim_end(), "a");
818+
assert_eq!(" ".trim_end(), "");
819+
assert_eq!("blah ".trim_end(), "blah");
820+
assert_eq!("wut \u{3000} ".trim_end(), "wut");
821+
assert_eq!(" hey".trim_end(), " hey");
822+
}
823+
774824
#[test]
775825
fn test_trim_left() {
776826
assert_eq!("".trim_left(), "");
@@ -1518,12 +1568,20 @@ fn trim_ws() {
15181568
"a \t ");
15191569
assert_eq!(" \t a \t ".trim_right_matches(|c: char| c.is_whitespace()),
15201570
" \t a");
1571+
assert_eq!(" \t a \t ".trim_start_matches(|c: char| c.is_whitespace()),
1572+
"a \t ");
1573+
assert_eq!(" \t a \t ".trim_end_matches(|c: char| c.is_whitespace()),
1574+
" \t a");
15211575
assert_eq!(" \t a \t ".trim_matches(|c: char| c.is_whitespace()),
15221576
"a");
15231577
assert_eq!(" \t \t ".trim_left_matches(|c: char| c.is_whitespace()),
15241578
"");
15251579
assert_eq!(" \t \t ".trim_right_matches(|c: char| c.is_whitespace()),
15261580
"");
1581+
assert_eq!(" \t \t ".trim_start_matches(|c: char| c.is_whitespace()),
1582+
"");
1583+
assert_eq!(" \t \t ".trim_end_matches(|c: char| c.is_whitespace()),
1584+
"");
15271585
assert_eq!(" \t \t ".trim_matches(|c: char| c.is_whitespace()),
15281586
"");
15291587
}

src/libcore/str/mod.rs

+159-13
Original file line numberDiff line numberDiff line change
@@ -3587,6 +3587,78 @@ impl str {
35873587
self.trim_matches(|c: char| c.is_whitespace())
35883588
}
35893589

3590+
/// Returns a string slice with leading whitespace removed.
3591+
///
3592+
/// 'Whitespace' is defined according to the terms of the Unicode Derived
3593+
/// Core Property `White_Space`.
3594+
///
3595+
/// # Text directionality
3596+
///
3597+
/// A string is a sequence of bytes. `start` in this context means the first
3598+
/// position of that byte string; for a left-to-right language like English or
3599+
/// Russian, this will be left side; and for right-to-left languages like
3600+
/// like Arabic or Hebrew, this will be the right side.
3601+
///
3602+
/// # Examples
3603+
///
3604+
/// Basic usage:
3605+
///
3606+
/// ```
3607+
/// let s = " Hello\tworld\t";
3608+
///
3609+
/// assert_eq!("Hello\tworld\t", s.trim_start());
3610+
/// ```
3611+
///
3612+
/// Directionality:
3613+
///
3614+
/// ```
3615+
/// let s = " English";
3616+
/// assert!(Some('E') == s.trim_start().chars().next());
3617+
///
3618+
/// let s = " עברית";
3619+
/// assert!(Some('ע') == s.trim_start().chars().next());
3620+
/// ```
3621+
#[unstable(feature = "trim_direction", issue = "30459")]
3622+
pub fn trim_start(&self) -> &str {
3623+
self.trim_start_matches(|c: char| c.is_whitespace())
3624+
}
3625+
3626+
/// Returns a string slice with trailing whitespace removed.
3627+
///
3628+
/// 'Whitespace' is defined according to the terms of the Unicode Derived
3629+
/// Core Property `White_Space`.
3630+
///
3631+
/// # Text directionality
3632+
///
3633+
/// A string is a sequence of bytes. `end` in this context means the last
3634+
/// position of that byte string; for a left-to-right language like English or
3635+
/// Russian, this will be right side; and for right-to-left languages like
3636+
/// like Arabic or Hebrew, this will be the left side.
3637+
///
3638+
/// # Examples
3639+
///
3640+
/// Basic usage:
3641+
///
3642+
/// ```
3643+
/// let s = " Hello\tworld\t";
3644+
///
3645+
/// assert_eq!(" Hello\tworld", s.trim_end());
3646+
/// ```
3647+
///
3648+
/// Directionality:
3649+
///
3650+
/// ```
3651+
/// let s = "English ";
3652+
/// assert!(Some('h') == s.trim_end().chars().rev().next());
3653+
///
3654+
/// let s = "עברית ";
3655+
/// assert!(Some('ת') == s.trim_end().chars().rev().next());
3656+
/// ```
3657+
#[unstable(feature = "trim_direction", issue = "30459")]
3658+
pub fn trim_end(&self) -> &str {
3659+
self.trim_end_matches(|c: char| c.is_whitespace())
3660+
}
3661+
35903662
/// Returns a string slice with leading whitespace removed.
35913663
///
35923664
/// 'Whitespace' is defined according to the terms of the Unicode Derived
@@ -3619,8 +3691,9 @@ impl str {
36193691
/// assert!(Some('ע') == s.trim_left().chars().next());
36203692
/// ```
36213693
#[stable(feature = "rust1", since = "1.0.0")]
3694+
#[rustc_deprecated(reason = "superseded by `trim_start`", since = "1.33.0")]
36223695
pub fn trim_left(&self) -> &str {
3623-
self.trim_left_matches(|c: char| c.is_whitespace())
3696+
self.trim_start()
36243697
}
36253698

36263699
/// Returns a string slice with trailing whitespace removed.
@@ -3655,8 +3728,9 @@ impl str {
36553728
/// assert!(Some('ת') == s.trim_right().chars().rev().next());
36563729
/// ```
36573730
#[stable(feature = "rust1", since = "1.0.0")]
3731+
#[rustc_deprecated(reason = "superseded by `trim_end`", since = "1.33.0")]
36583732
pub fn trim_right(&self) -> &str {
3659-
self.trim_right_matches(|c: char| c.is_whitespace())
3733+
self.trim_end()
36603734
}
36613735

36623736
/// Returns a string slice with all prefixes and suffixes that match a
@@ -3725,14 +3799,14 @@ impl str {
37253799
/// Basic usage:
37263800
///
37273801
/// ```
3728-
/// assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11");
3729-
/// assert_eq!("123foo1bar123".trim_left_matches(char::is_numeric), "foo1bar123");
3802+
/// assert_eq!("11foo1bar11".trim_start_matches('1'), "foo1bar11");
3803+
/// assert_eq!("123foo1bar123".trim_start_matches(char::is_numeric), "foo1bar123");
37303804
///
37313805
/// let x: &[_] = &['1', '2'];
3732-
/// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12");
3806+
/// assert_eq!("12foo1bar12".trim_start_matches(x), "foo1bar12");
37333807
/// ```
3734-
#[stable(feature = "rust1", since = "1.0.0")]
3735-
pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
3808+
#[unstable(feature = "trim_direction", issue = "30459")]
3809+
pub fn trim_start_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
37363810
let mut i = self.len();
37373811
let mut matcher = pat.into_searcher(self);
37383812
if let Some((a, _)) = matcher.next_reject() {
@@ -3764,20 +3838,20 @@ impl str {
37643838
/// Simple patterns:
37653839
///
37663840
/// ```
3767-
/// assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar");
3768-
/// assert_eq!("123foo1bar123".trim_right_matches(char::is_numeric), "123foo1bar");
3841+
/// assert_eq!("11foo1bar11".trim_end_matches('1'), "11foo1bar");
3842+
/// assert_eq!("123foo1bar123".trim_end_matches(char::is_numeric), "123foo1bar");
37693843
///
37703844
/// let x: &[_] = &['1', '2'];
3771-
/// assert_eq!("12foo1bar12".trim_right_matches(x), "12foo1bar");
3845+
/// assert_eq!("12foo1bar12".trim_end_matches(x), "12foo1bar");
37723846
/// ```
37733847
///
37743848
/// A more complex pattern, using a closure:
37753849
///
37763850
/// ```
3777-
/// assert_eq!("1fooX".trim_right_matches(|c| c == '1' || c == 'X'), "1foo");
3851+
/// assert_eq!("1fooX".trim_end_matches(|c| c == '1' || c == 'X'), "1foo");
37783852
/// ```
3779-
#[stable(feature = "rust1", since = "1.0.0")]
3780-
pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
3853+
#[unstable(feature = "trim_direction", issue = "30459")]
3854+
pub fn trim_end_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
37813855
where P::Searcher: ReverseSearcher<'a>
37823856
{
37833857
let mut j = 0;
@@ -3791,6 +3865,78 @@ impl str {
37913865
}
37923866
}
37933867

3868+
/// Returns a string slice with all prefixes that match a pattern
3869+
/// repeatedly removed.
3870+
///
3871+
/// The pattern can be a `&str`, [`char`], or a closure that determines if
3872+
/// a character matches.
3873+
///
3874+
/// [`char`]: primitive.char.html
3875+
///
3876+
/// # Text directionality
3877+
///
3878+
/// A string is a sequence of bytes. 'Left' in this context means the first
3879+
/// position of that byte string; for a language like Arabic or Hebrew
3880+
/// which are 'right to left' rather than 'left to right', this will be
3881+
/// the _right_ side, not the left.
3882+
///
3883+
/// # Examples
3884+
///
3885+
/// Basic usage:
3886+
///
3887+
/// ```
3888+
/// assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11");
3889+
/// assert_eq!("123foo1bar123".trim_left_matches(char::is_numeric), "foo1bar123");
3890+
///
3891+
/// let x: &[_] = &['1', '2'];
3892+
/// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12");
3893+
/// ```
3894+
#[stable(feature = "rust1", since = "1.0.0")]
3895+
#[rustc_deprecated(reason = "superseded by `trim_start_matches`", since = "1.33.0")]
3896+
pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
3897+
self.trim_start_matches(pat)
3898+
}
3899+
3900+
/// Returns a string slice with all suffixes that match a pattern
3901+
/// repeatedly removed.
3902+
///
3903+
/// The pattern can be a `&str`, [`char`], or a closure that
3904+
/// determines if a character matches.
3905+
///
3906+
/// [`char`]: primitive.char.html
3907+
///
3908+
/// # Text directionality
3909+
///
3910+
/// A string is a sequence of bytes. 'Right' in this context means the last
3911+
/// position of that byte string; for a language like Arabic or Hebrew
3912+
/// which are 'right to left' rather than 'left to right', this will be
3913+
/// the _left_ side, not the right.
3914+
///
3915+
/// # Examples
3916+
///
3917+
/// Simple patterns:
3918+
///
3919+
/// ```
3920+
/// assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar");
3921+
/// assert_eq!("123foo1bar123".trim_right_matches(char::is_numeric), "123foo1bar");
3922+
///
3923+
/// let x: &[_] = &['1', '2'];
3924+
/// assert_eq!("12foo1bar12".trim_right_matches(x), "12foo1bar");
3925+
/// ```
3926+
///
3927+
/// A more complex pattern, using a closure:
3928+
///
3929+
/// ```
3930+
/// assert_eq!("1fooX".trim_right_matches(|c| c == '1' || c == 'X'), "1foo");
3931+
/// ```
3932+
#[stable(feature = "rust1", since = "1.0.0")]
3933+
#[rustc_deprecated(reason = "superseded by `trim_end_matches`", since = "1.33.0")]
3934+
pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
3935+
where P::Searcher: ReverseSearcher<'a>
3936+
{
3937+
self.trim_end_matches(pat)
3938+
}
3939+
37943940
/// Parses this string slice into another type.
37953941
///
37963942
/// Because `parse` is so general, it can cause problems with type

0 commit comments

Comments
 (0)