Running a series of consecutive replacements on one line

I found this example to replace a substring:

use std::str; let string = "orange"; let new_string = str::replace(string, "or", "str"); 

If I want to run several consecutive replacements on the same line, for sanitation purposes, how can I do this without allocating a new variable for each replacement?

If you wrote about the idiomatic Rust, how would you write a substring replacement with multiple chains?

+5
source share
3 answers

how would you write a substring substitution with multiple chains?

I would do it the same way I asked:

 fn main() { let a = "hello"; let b = a.replace("e", "a").replace("ll", "r").replace("o", "d"); println!("{}", b); } 

It is you asking how to do multiple simultaneous replacements, going through a line only once, then it really becomes much more complicated.

This requires allocating new memory for each replace call, even if replacement is not required. An alternative implementation of replace can return a Cow<str> , which only includes the owned option when the replacement occurs. A hacker implementation of this might look like this:

 use std::borrow::Cow; trait MaybeReplaceExt<'a> { fn maybe_replace(self, needle: &str, replacement: &str) -> Cow<'a, str>; } impl<'a> MaybeReplaceExt<'a> for &'a str { fn maybe_replace(self, needle: &str, replacement: &str) -> Cow<'a, str> { // Assumes that searching twice is better than unconditionally allocating if self.contains(needle) { self.replace(needle, replacement).into() } else { self.into() } } } impl<'a> MaybeReplaceExt<'a> for Cow<'a, str> { fn maybe_replace(self, needle: &str, replacement: &str) -> Cow<'a, str> { // Assumes that searching twice is better than unconditionally allocating if self.contains(needle) { self.replace(needle, replacement).into() } else { self } } } fn main() { let a = "hello"; let b = a.maybe_replace("e", "a") .maybe_replace("ll", "r") .maybe_replace("o", "d"); println!("{}", b); let a = "hello"; let b = a.maybe_replace("nope", "not here") .maybe_replace("still no", "i swear") .maybe_replace("but no", "allocation"); println!("{}", b); assert_eq!(b.as_ptr(), a.as_ptr()); } 
+3
source

There is no way in the standard library to do this; its a difficult thing to get right with a lot of variations on how you will do it, depending on a number of factors. You will need to write such a function yourself.

+3
source

The regex engine can be used for a single pass with multiple line replacements, although I would be surprised if this is actually more efficient:

 extern crate regex; use regex::{Captures, Regex}; fn main() { let re = Regex::new("(or|e)").unwrap(); let string = "orange"; let result = re.replace_all(string, |cap: &Captures| { match &cap[0] { "or" => "str", "e" => "er", _ => panic!("We should never get here"), }.to_string() }); println!("{}", result); } 
+3
source

Source: https://habr.com/ru/post/1209043/


All Articles