Skip to content

Commit 16ff9e2

Browse files
authored
Auto merge of #36347 - knight42:str-replacen, r=alexcrichton
Implement std::str::replacen Replaces first N matches of a pattern with another string. ``` assert_eq!("acaaa".replacen(a, "b", 3), "bcbba") ```
2 parents 6ffdda1 + ebda770 commit 16ff9e2

File tree

3 files changed

+58
-0
lines changed

3 files changed

+58
-0
lines changed

src/libcollections/str.rs

+43
Original file line numberDiff line numberDiff line change
@@ -1594,6 +1594,49 @@ impl str {
15941594
result
15951595
}
15961596

1597+
/// Replaces first N matches of a pattern with another string.
1598+
///
1599+
/// `replacen` creates a new [`String`], and copies the data from this string slice into it.
1600+
/// While doing so, it attempts to find matches of a pattern. If it finds any, it
1601+
/// replaces them with the replacement string slice at most `N` times.
1602+
///
1603+
/// [`String`]: string/struct.String.html
1604+
///
1605+
/// # Examples
1606+
///
1607+
/// Basic usage:
1608+
///
1609+
/// ```
1610+
/// # #![feature(str_replacen)]
1611+
/// let s = "foo foo 123 foo";
1612+
/// assert_eq!("new new 123 foo", s.replacen("foo", "new", 2));
1613+
/// assert_eq!("faa fao 123 foo", s.replacen('o', "a", 3));
1614+
/// assert_eq!("foo foo new23 foo", s.replacen(char::is_numeric, "new", 1));
1615+
/// ```
1616+
///
1617+
/// When the pattern doesn't match:
1618+
///
1619+
/// ```
1620+
/// # #![feature(str_replacen)]
1621+
/// let s = "this is old";
1622+
/// assert_eq!(s, s.replacen("cookie monster", "little lamb", 10));
1623+
/// ```
1624+
#[unstable(feature = "str_replacen",
1625+
issue = "36436",
1626+
reason = "only need to replace first N matches")]
1627+
pub fn replacen<'a, P: Pattern<'a>>(&'a self, pat: P, to: &str, count: usize) -> String {
1628+
// Hope to reduce the times of re-allocation
1629+
let mut result = String::with_capacity(32);
1630+
let mut last_end = 0;
1631+
for (start, part) in self.match_indices(pat).take(count) {
1632+
result.push_str(unsafe { self.slice_unchecked(last_end, start) });
1633+
result.push_str(to);
1634+
last_end = start + part.len();
1635+
}
1636+
result.push_str(unsafe { self.slice_unchecked(last_end, self.len()) });
1637+
result
1638+
}
1639+
15971640
/// Returns the lowercase equivalent of this string slice, as a new [`String`].
15981641
///
15991642
/// 'Lowercase' is defined according to the terms of the Unicode Derived Core Property

src/libcollectionstest/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#![feature(rand)]
2222
#![feature(step_by)]
2323
#![feature(str_escape)]
24+
#![feature(str_replacen)]
2425
#![feature(test)]
2526
#![feature(unboxed_closures)]
2627
#![feature(unicode)]

src/libcollectionstest/str.rs

+14
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,20 @@ fn test_is_empty() {
218218
assert!(!"a".is_empty());
219219
}
220220

221+
#[test]
222+
fn test_replacen() {
223+
assert_eq!("".replacen('a', "b", 5), "");
224+
assert_eq!("acaaa".replacen("a", "b", 3), "bcbba");
225+
assert_eq!("aaaa".replacen("a", "b", 0), "aaaa");
226+
227+
let test = "test";
228+
assert_eq!(" test test ".replacen(test, "toast", 3), " toast toast ");
229+
assert_eq!(" test test ".replacen(test, "toast", 0), " test test ");
230+
assert_eq!(" test test ".replacen(test, "", 5), " ");
231+
232+
assert_eq!("qwer123zxc789".replacen(char::is_numeric, "", 3), "qwerzxc789");
233+
}
234+
221235
#[test]
222236
fn test_replace() {
223237
let a = "a";

0 commit comments

Comments
 (0)