Skip to content

Commit 1c12dc8

Browse files
authored
Rollup merge of rust-lang#66735 - SOF3:feature/str_strip, r=KodrAus
Add str::strip_prefix and str::strip_suffix Introduces a counterpart for `Path::strip_prefix` on `str`. This was also discussed in https://internals.rust-lang.org/t/pre-pr-path-strip-prefix-counterpart-in-str/11364/.
2 parents 84ef889 + 6176051 commit 1c12dc8

File tree

1 file changed

+72
-1
lines changed

1 file changed

+72
-1
lines changed

src/libcore/str/mod.rs

+72-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#![stable(feature = "rust1", since = "1.0.0")]
99

1010
use self::pattern::Pattern;
11-
use self::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher};
11+
use self::pattern::{Searcher, SearchStep, ReverseSearcher, DoubleEndedSearcher};
1212

1313
use crate::char;
1414
use crate::fmt::{self, Write};
@@ -3798,6 +3798,77 @@ impl str {
37983798
}
37993799
}
38003800

3801+
/// Returns a string slice with the prefix removed.
3802+
///
3803+
/// If the string starts with the pattern `prefix`, `Some` is returned with the substring where
3804+
/// the prefix is removed. Unlike `trim_start_matches`, this method removes the prefix exactly
3805+
/// once.
3806+
///
3807+
/// If the string does not start with `prefix`, `None` is returned.
3808+
///
3809+
/// # Examples
3810+
///
3811+
/// ```
3812+
/// #![feature(str_strip)]
3813+
///
3814+
/// assert_eq!("foobar".strip_prefix("foo"), Some("bar"));
3815+
/// assert_eq!("foobar".strip_prefix("bar"), None);
3816+
/// assert_eq!("foofoo".strip_prefix("foo"), Some("foo"));
3817+
/// ```
3818+
#[must_use = "this returns the remaining substring as a new slice, \
3819+
without modifying the original"]
3820+
#[unstable(feature = "str_strip", reason = "newly added", issue = "67302")]
3821+
pub fn strip_prefix<'a, P: Pattern<'a>>(&'a self, prefix: P) -> Option<&'a str> {
3822+
let mut matcher = prefix.into_searcher(self);
3823+
if let SearchStep::Match(start, len) = matcher.next() {
3824+
debug_assert_eq!(start, 0, "The first search step from Searcher \
3825+
must include the first character");
3826+
unsafe {
3827+
// Searcher is known to return valid indices.
3828+
Some(self.get_unchecked(len..))
3829+
}
3830+
} else {
3831+
None
3832+
}
3833+
}
3834+
3835+
/// Returns a string slice with the suffix removed.
3836+
///
3837+
/// If the string ends with the pattern `suffix`, `Some` is returned with the substring where
3838+
/// the suffix is removed. Unlike `trim_end_matches`, this method removes the suffix exactly
3839+
/// once.
3840+
///
3841+
/// If the string does not end with `suffix`, `None` is returned.
3842+
///
3843+
/// # Examples
3844+
///
3845+
/// ```
3846+
/// #![feature(str_strip)]
3847+
/// assert_eq!("barfoo".strip_suffix("foo"), Some("bar"));
3848+
/// assert_eq!("barfoo".strip_suffix("bar"), None);
3849+
/// assert_eq!("foofoo".strip_suffix("foo"), Some("foo"));
3850+
/// ```
3851+
#[must_use = "this returns the remaining substring as a new slice, \
3852+
without modifying the original"]
3853+
#[unstable(feature = "str_strip", reason = "newly added", issue = "67302")]
3854+
pub fn strip_suffix<'a, P>(&'a self, suffix: P) -> Option<&'a str>
3855+
where
3856+
P: Pattern<'a>,
3857+
<P as Pattern<'a>>::Searcher: ReverseSearcher<'a>,
3858+
{
3859+
let mut matcher = suffix.into_searcher(self);
3860+
if let SearchStep::Match(start, end) = matcher.next_back() {
3861+
debug_assert_eq!(end, self.len(), "The first search step from ReverseSearcher \
3862+
must include the last character");
3863+
unsafe {
3864+
// Searcher is known to return valid indices.
3865+
Some(self.get_unchecked(..start))
3866+
}
3867+
} else {
3868+
None
3869+
}
3870+
}
3871+
38013872
/// Returns a string slice with all suffixes that match a pattern
38023873
/// repeatedly removed.
38033874
///

0 commit comments

Comments
 (0)