Skip to content

Commit a2902ed

Browse files
Add String::replace_first and String::replace_last
Rebased by zachs18. Co-authored-by: zachs18 <8355914+zachs18@users.noreply.github.com>
1 parent f1ec5d6 commit a2902ed

File tree

4 files changed

+93
-0
lines changed

4 files changed

+93
-0
lines changed

library/alloc/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@
134134
#![feature(ptr_internals)]
135135
#![feature(ptr_metadata)]
136136
#![feature(ptr_sub_ptr)]
137+
#![feature(string_replace_in_place)]
137138
#![feature(set_ptr_value)]
138139
#![feature(sized_type_properties)]
139140
#![feature(slice_from_ptr_range)]

library/alloc/src/string.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2003,6 +2003,63 @@ impl String {
20032003
unsafe { self.as_mut_vec() }.splice((start, end), replace_with.bytes());
20042004
}
20052005

2006+
/// Replaces the leftmost occurrence of a pattern with another string, in-place.
2007+
///
2008+
/// This method should be preferred over [`String::replacen(..., 1)`](str::replacen) as it can use the `String`'s existing capacity to prevent a reallocation if sufficient space is available.
2009+
///
2010+
/// # Examples
2011+
///
2012+
/// Basic usage:
2013+
///
2014+
/// ```
2015+
/// #![feature(string_replace_in_place)]
2016+
///
2017+
/// let mut s = String::from("Test Results: ❌❌❌");
2018+
///
2019+
/// // Replace the leftmost ❌ with a ✅
2020+
/// s.replace_first('❌', "✅");
2021+
/// assert_eq!(s, "Test Results: ✅❌❌");
2022+
/// ```
2023+
#[cfg(not(no_global_oom_handling))]
2024+
#[unstable(feature = "string_replace_in_place", issue = "none")]
2025+
pub fn replace_first<P: Pattern>(&mut self, from: P, to: &str) {
2026+
let range = match self.match_indices(from).next() {
2027+
Some((start, match_str)) => start..start + match_str.len(),
2028+
None => return,
2029+
};
2030+
2031+
self.replace_range(range, to);
2032+
}
2033+
2034+
/// Replaces the rightmost occurrence of a pattern with another string, in-place.
2035+
///
2036+
/// # Examples
2037+
///
2038+
/// Basic usage:
2039+
///
2040+
/// ```
2041+
/// #![feature(string_replace_in_place)]
2042+
///
2043+
/// let mut s = String::from("Test Results: ❌❌❌");
2044+
///
2045+
/// // Replace the rightmost ❌ with a ✅
2046+
/// s.replace_last('❌', "✅");
2047+
/// assert_eq!(s, "Test Results: ❌❌✅");
2048+
/// ```
2049+
#[cfg(not(no_global_oom_handling))]
2050+
#[unstable(feature = "string_replace_in_place", issue = "none")]
2051+
pub fn replace_last<P: Pattern>(&mut self, from: P, to: &str)
2052+
where
2053+
for<'a> P::Searcher<'a>: core::str::pattern::ReverseSearcher<'a>,
2054+
{
2055+
let range = match self.rmatch_indices(from).next() {
2056+
Some((start, match_str)) => start..start + match_str.len(),
2057+
None => return,
2058+
};
2059+
2060+
self.replace_range(range, to);
2061+
}
2062+
20062063
/// Converts this `String` into a <code>[Box]<[str]></code>.
20072064
///
20082065
/// Before doing the conversion, this method discards excess capacity like [`shrink_to_fit`].

library/alloc/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#![feature(local_waker)]
3838
#![feature(str_as_str)]
3939
#![feature(strict_provenance_lints)]
40+
#![feature(string_replace_in_place)]
4041
#![feature(vec_pop_if)]
4142
#![feature(unique_rc_arc)]
4243
#![feature(macro_metavar_expr_concat)]

library/alloc/tests/string.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,40 @@ fn test_replace_range_evil_end_bound() {
710710
assert_eq!(Ok(""), str::from_utf8(s.as_bytes()));
711711
}
712712

713+
#[test]
714+
fn test_replace_first() {
715+
let mut s = String::from("~ First ❌ Middle ❌ Last ❌ ~");
716+
s.replace_first("❌", "✅✅");
717+
assert_eq!(s, "~ First ✅✅ Middle ❌ Last ❌ ~");
718+
s.replace_first("🦀", "😳");
719+
assert_eq!(s, "~ First ✅✅ Middle ❌ Last ❌ ~");
720+
721+
let mut s = String::from("❌");
722+
s.replace_first('❌', "✅✅");
723+
assert_eq!(s, "✅✅");
724+
725+
let mut s = String::from("");
726+
s.replace_first('🌌', "❌");
727+
assert_eq!(s, "");
728+
}
729+
730+
#[test]
731+
fn test_replace_last() {
732+
let mut s = String::from("~ First ❌ Middle ❌ Last ❌ ~");
733+
s.replace_last("❌", "✅✅");
734+
assert_eq!(s, "~ First ❌ Middle ❌ Last ✅✅ ~");
735+
s.replace_last("🦀", "😳");
736+
assert_eq!(s, "~ First ❌ Middle ❌ Last ✅✅ ~");
737+
738+
let mut s = String::from("❌");
739+
s.replace_last::<char>('❌', "✅✅");
740+
assert_eq!(s, "✅✅");
741+
742+
let mut s = String::from("");
743+
s.replace_last::<char>('🌌', "❌");
744+
assert_eq!(s, "");
745+
}
746+
713747
#[test]
714748
fn test_extend_ref() {
715749
let mut a = "foo".to_string();

0 commit comments

Comments
 (0)