Rollup merge of #142331 - deven:trim_prefix_suffix, r=Amanieu
Add `trim_prefix` and `trim_suffix` methods for both `slice` and `str` types. Implements `trim_prefix` and `trim_suffix` methods for both `slice` and `str` types, which remove at most one occurrence of a prefix/suffix while always returning a string/slice (rather than Option), enabling easy method chaining. ## Tracking issue rust-lang/rust#142312 ## API ```rust impl str { pub fn trim_prefix<P: Pattern>(&self, prefix: P) -> &str; pub fn trim_suffix<P: Pattern>(&self, suffix: P) -> &str where for<'a> P::Searcher<'a>: ReverseSearcher<'a>; } impl<T> [T] { pub fn trim_prefix<P: SlicePattern<Item = T> + ?Sized>(&self, prefix: &P) -> &[T] where T: PartialEq; pub fn trim_suffix<P: SlicePattern<Item = T> + ?Sized>(&self, suffix: &P) -> &[T] where T: PartialEq; } ``` ## Examples ```rust // Method chaining assert_eq!(" <https://example.com/> ".trim().trim_prefix('<').trim_suffix('>').trim(), "https://example.com/"); // Slices let v = &[10, 40, 30]; assert_eq!(v.trim_prefix(&[10]), &[40, 30][..]); ``` ## ACP Originally proposed in rust-lang/libs-team#597
This commit is contained in:
commit
851fbcb092
2 changed files with 160 additions and 0 deletions
|
|
@ -2764,6 +2764,89 @@ impl<T> [T] {
|
|||
None
|
||||
}
|
||||
|
||||
/// Returns a subslice with the optional prefix removed.
|
||||
///
|
||||
/// If the slice starts with `prefix`, returns the subslice after the prefix. If `prefix`
|
||||
/// is empty or the slice does not start with `prefix`, simply returns the original slice.
|
||||
/// If `prefix` is equal to the original slice, returns an empty slice.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(trim_prefix_suffix)]
|
||||
///
|
||||
/// let v = &[10, 40, 30];
|
||||
///
|
||||
/// // Prefix present - removes it
|
||||
/// assert_eq!(v.trim_prefix(&[10]), &[40, 30][..]);
|
||||
/// assert_eq!(v.trim_prefix(&[10, 40]), &[30][..]);
|
||||
/// assert_eq!(v.trim_prefix(&[10, 40, 30]), &[][..]);
|
||||
///
|
||||
/// // Prefix absent - returns original slice
|
||||
/// assert_eq!(v.trim_prefix(&[50]), &[10, 40, 30][..]);
|
||||
/// assert_eq!(v.trim_prefix(&[10, 50]), &[10, 40, 30][..]);
|
||||
///
|
||||
/// let prefix : &str = "he";
|
||||
/// assert_eq!(b"hello".trim_prefix(prefix.as_bytes()), b"llo".as_ref());
|
||||
/// ```
|
||||
#[must_use = "returns the subslice without modifying the original"]
|
||||
#[unstable(feature = "trim_prefix_suffix", issue = "142312")]
|
||||
pub fn trim_prefix<P: SlicePattern<Item = T> + ?Sized>(&self, prefix: &P) -> &[T]
|
||||
where
|
||||
T: PartialEq,
|
||||
{
|
||||
// This function will need rewriting if and when SlicePattern becomes more sophisticated.
|
||||
let prefix = prefix.as_slice();
|
||||
let n = prefix.len();
|
||||
if n <= self.len() {
|
||||
let (head, tail) = self.split_at(n);
|
||||
if head == prefix {
|
||||
return tail;
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns a subslice with the optional suffix removed.
|
||||
///
|
||||
/// If the slice ends with `suffix`, returns the subslice before the suffix. If `suffix`
|
||||
/// is empty or the slice does not end with `suffix`, simply returns the original slice.
|
||||
/// If `suffix` is equal to the original slice, returns an empty slice.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(trim_prefix_suffix)]
|
||||
///
|
||||
/// let v = &[10, 40, 30];
|
||||
///
|
||||
/// // Suffix present - removes it
|
||||
/// assert_eq!(v.trim_suffix(&[30]), &[10, 40][..]);
|
||||
/// assert_eq!(v.trim_suffix(&[40, 30]), &[10][..]);
|
||||
/// assert_eq!(v.trim_suffix(&[10, 40, 30]), &[][..]);
|
||||
///
|
||||
/// // Suffix absent - returns original slice
|
||||
/// assert_eq!(v.trim_suffix(&[50]), &[10, 40, 30][..]);
|
||||
/// assert_eq!(v.trim_suffix(&[50, 30]), &[10, 40, 30][..]);
|
||||
/// ```
|
||||
#[must_use = "returns the subslice without modifying the original"]
|
||||
#[unstable(feature = "trim_prefix_suffix", issue = "142312")]
|
||||
pub fn trim_suffix<P: SlicePattern<Item = T> + ?Sized>(&self, suffix: &P) -> &[T]
|
||||
where
|
||||
T: PartialEq,
|
||||
{
|
||||
// This function will need rewriting if and when SlicePattern becomes more sophisticated.
|
||||
let suffix = suffix.as_slice();
|
||||
let (len, n) = (self.len(), suffix.len());
|
||||
if n <= len {
|
||||
let (head, tail) = self.split_at(len - n);
|
||||
if tail == suffix {
|
||||
return head;
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Binary searches this slice for a given element.
|
||||
/// If the slice is not sorted, the returned result is unspecified and
|
||||
/// meaningless.
|
||||
|
|
|
|||
|
|
@ -2426,6 +2426,83 @@ impl str {
|
|||
suffix.strip_suffix_of(self)
|
||||
}
|
||||
|
||||
/// Returns a string slice with the optional prefix removed.
|
||||
///
|
||||
/// If the string starts with the pattern `prefix`, returns the substring after the prefix.
|
||||
/// Unlike [`strip_prefix`], this method always returns `&str` for easy method chaining,
|
||||
/// instead of returning [`Option<&str>`].
|
||||
///
|
||||
/// If the string does not start with `prefix`, returns the original string unchanged.
|
||||
///
|
||||
/// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
|
||||
/// function or closure that determines if a character matches.
|
||||
///
|
||||
/// [`char`]: prim@char
|
||||
/// [pattern]: self::pattern
|
||||
/// [`strip_prefix`]: Self::strip_prefix
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(trim_prefix_suffix)]
|
||||
///
|
||||
/// // Prefix present - removes it
|
||||
/// assert_eq!("foo:bar".trim_prefix("foo:"), "bar");
|
||||
/// assert_eq!("foofoo".trim_prefix("foo"), "foo");
|
||||
///
|
||||
/// // Prefix absent - returns original string
|
||||
/// assert_eq!("foo:bar".trim_prefix("bar"), "foo:bar");
|
||||
///
|
||||
/// // Method chaining example
|
||||
/// assert_eq!("<https://example.com/>".trim_prefix('<').trim_suffix('>'), "https://example.com/");
|
||||
/// ```
|
||||
#[must_use = "this returns the remaining substring as a new slice, \
|
||||
without modifying the original"]
|
||||
#[unstable(feature = "trim_prefix_suffix", issue = "142312")]
|
||||
pub fn trim_prefix<P: Pattern>(&self, prefix: P) -> &str {
|
||||
prefix.strip_prefix_of(self).unwrap_or(self)
|
||||
}
|
||||
|
||||
/// Returns a string slice with the optional suffix removed.
|
||||
///
|
||||
/// If the string ends with the pattern `suffix`, returns the substring before the suffix.
|
||||
/// Unlike [`strip_suffix`], this method always returns `&str` for easy method chaining,
|
||||
/// instead of returning [`Option<&str>`].
|
||||
///
|
||||
/// If the string does not end with `suffix`, returns the original string unchanged.
|
||||
///
|
||||
/// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a
|
||||
/// function or closure that determines if a character matches.
|
||||
///
|
||||
/// [`char`]: prim@char
|
||||
/// [pattern]: self::pattern
|
||||
/// [`strip_suffix`]: Self::strip_suffix
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(trim_prefix_suffix)]
|
||||
///
|
||||
/// // Suffix present - removes it
|
||||
/// assert_eq!("bar:foo".trim_suffix(":foo"), "bar");
|
||||
/// assert_eq!("foofoo".trim_suffix("foo"), "foo");
|
||||
///
|
||||
/// // Suffix absent - returns original string
|
||||
/// assert_eq!("bar:foo".trim_suffix("bar"), "bar:foo");
|
||||
///
|
||||
/// // Method chaining example
|
||||
/// assert_eq!("<https://example.com/>".trim_prefix('<').trim_suffix('>'), "https://example.com/");
|
||||
/// ```
|
||||
#[must_use = "this returns the remaining substring as a new slice, \
|
||||
without modifying the original"]
|
||||
#[unstable(feature = "trim_prefix_suffix", issue = "142312")]
|
||||
pub fn trim_suffix<P: Pattern>(&self, suffix: P) -> &str
|
||||
where
|
||||
for<'a> P::Searcher<'a>: ReverseSearcher<'a>,
|
||||
{
|
||||
suffix.strip_suffix_of(self).unwrap_or(self)
|
||||
}
|
||||
|
||||
/// Returns a string slice with all suffixes that match a pattern
|
||||
/// repeatedly removed.
|
||||
///
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue