在同一个字符串上运行多个连续替换

时间:2014-12-15 03:21:22

标签: rust

我找到了这个替换子字符串的例子:

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

如果我想在同一个字符串上运行多个连续替换,为了清理目的,如何在不为每次替换分配新变量的情况下执行此操作?

如果您要编写惯用的Rust,您将如何编写多个链式子串替换?

3 个答案:

答案 0 :(得分:4)

  

你会如何编写多个链式子串替换?

我会按照要求这样做:

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

你问的是如何做多个并发替换,只通过一次字符串,然后它确实让更难。

这确实需要为每个replace呼叫分配新内存,即使不需要替换也是如此。 replace的替代实现可能返回Cow<str>,其仅在替换发生时包含所拥有的变体。一个hacky实现可能看起来像:

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());
}

答案 1 :(得分:3)

标准库中没有办法做到这一点;根据许多因素,对于如何做到这一点,要做出大量变化是一件非常棘手的事情。您需要自己编写这样的函数。

答案 2 :(得分:3)

regex engine可以用来做多次替换字符串的单次传递,但如果这实际上更高效,我会感到惊讶:

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);
}