I found this example for substring replacement:
use std::str;
let string = \"orange\";
let new_string = str::replace(string, \"or\", \"str\");
There is no way in the standard library to do this; it’s a tricky thing to get right with a large number of variations on how you would go about doing it, depending on a number of factors. You would need to write such a function yourself.
The regex engine can be used to do a single pass with multiple replacements of the string, though I would be surprised if this is actually more performant:
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);
}
how would you write multiple chained substring replacements?
I would do it just as asked:
fn main() {
let a = "hello";
let b = a.replace("e", "a").replace("ll", "r").replace("o", "d");
println!("{}", b);
}
It you are asking how to do multiple concurrent replacements, passing through the string just once, then it does indeed get much harder.
This does require allocating new memory for each replace
call, even if no replacement was needed. An alternate implementation of replace
might return a Cow<str> which only includes the owned variant when the replacement would occur. A hacky implementation of that could look like:
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());
}