about summary refs log tree commit diff
path: root/library/alloc/src/string.rs
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-03-19 00:47:37 +0000
committerbors <bors@rust-lang.org>2021-03-19 00:47:37 +0000
commiteb95acea8aeaeef834214eaffb15d64095fe9271 (patch)
tree1e13b205c657ee7584e35bf301bace177ef64bc5 /library/alloc/src/string.rs
parent1705a7d64b833d1c4b69958b0627bd054e6d764b (diff)
parenta2571cfc8b6f5cf5d8d2e7075ac4809aceae9541 (diff)
downloadrust-eb95acea8aeaeef834214eaffb15d64095fe9271.tar.gz
rust-eb95acea8aeaeef834214eaffb15d64095fe9271.zip
Auto merge of #71780 - jcotton42:string_remove_matches, r=joshtriplett
Implement String::remove_matches

Closes #50206.

I lifted the function help from `@frewsxcv's` original PR (#50015), hope they don't mind.

I'm also wondering whether it would be useful for `remove_matches` to collect up the removed substrings into a `Vec` and return them, right now they're just overwritten by the copy and lost.
Diffstat (limited to 'library/alloc/src/string.rs')
-rw-r--r--library/alloc/src/string.rs56
1 files changed, 56 insertions, 0 deletions
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index e2e705d7980..019b17a5945 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -1202,6 +1202,62 @@ impl String {
         ch
     }
 
+    /// Remove all matches of pattern `pat` in the `String`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(string_remove_matches)]
+    /// let mut s = String::from("Trees are not green, the sky is not blue.");
+    /// s.remove_matches("not ");
+    /// assert_eq!("Trees are green, the sky is blue.", s);
+    /// ```
+    ///
+    /// Matches will be detected and removed iteratively, so in cases where
+    /// patterns overlap, only the first pattern will be removed:
+    ///
+    /// ```
+    /// #![feature(string_remove_matches)]
+    /// let mut s = String::from("banana");
+    /// s.remove_matches("ana");
+    /// assert_eq!("bna", s);
+    /// ```
+    #[unstable(feature = "string_remove_matches", reason = "new API", issue = "72826")]
+    pub fn remove_matches<'a, P>(&'a mut self, pat: P)
+    where
+        P: for<'x> Pattern<'x>,
+    {
+        use core::str::pattern::Searcher;
+
+        let matches = {
+            let mut searcher = pat.into_searcher(self);
+            let mut matches = Vec::new();
+
+            while let Some(m) = searcher.next_match() {
+                matches.push(m);
+            }
+
+            matches
+        };
+
+        let len = self.len();
+        let mut shrunk_by = 0;
+
+        // SAFETY: start and end will be on utf8 byte boundaries per
+        // the Searcher docs
+        unsafe {
+            for (start, end) in matches {
+                ptr::copy(
+                    self.vec.as_mut_ptr().add(end - shrunk_by),
+                    self.vec.as_mut_ptr().add(start - shrunk_by),
+                    len - end,
+                );
+                shrunk_by += end - start;
+            }
+            self.vec.set_len(len - shrunk_by);
+        }
+    }
+
     /// Retains only the characters specified by the predicate.
     ///
     /// In other words, remove all characters `c` such that `f(c)` returns `false`.