Running a number of consecutive replacements on the same string

前端 未结 3 327
盖世英雄少女心
盖世英雄少女心 2021-01-12 08:43

I found this example for substring replacement:

use std::str;
let string = \"orange\";
let new_string = str::replace(string, \"or\", \"str\");
相关标签:
3条回答
  • 2021-01-12 09:28

    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.

    0 讨论(0)
  • 2021-01-12 09:35

    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);
    }
    
    0 讨论(0)
  • 2021-01-12 09:42

    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());
    }
    
    0 讨论(0)
提交回复
热议问题