Anders
Anders

Reputation: 8577

Replacing numbered placeholders with elements of a vector in Rust?

I have the following:

I want to get a version of my &str where all occurences of $i are replaced by the ith element of the vector. So if I have vec!["foo", "bar"] and $0$1, the result would be foobar.

My first naive approach was to iterate over i = 1..N and do a search and replace for every index. However, this is a quite ugly and inefficient solution. Also, it gives undesired outputs if any of the values in the vector contains the $ character.

Is there a better way to do this in Rust?

Upvotes: 0

Views: 802

Answers (2)

Anders
Anders

Reputation: 8577

This solution is inspired (including copied test cases) by Shepmaster's, but simplifies things by using the replace_all method.

use regex::{Regex, Captures};

fn template_replace(template: &str, values: &[&str]) -> String {
    let regex = Regex::new(r#"\$(\d+)"#).unwrap();
    regex.replace_all(template, |captures: &Captures| {
        values
            .get(index(captures))
            .unwrap_or(&"")
    }).to_string()
}

fn index(captures: &Captures) -> usize {
    captures.get(1)
        .unwrap()
        .as_str()
        .parse()
        .unwrap()
}

fn main() {
    assert_eq!("ab", template_replace("$0$1", &["a", "b"]));
    assert_eq!("$1b", template_replace("$0$1", &["$1", "b"]));
    assert_eq!("moo", template_replace("moo", &[]));
    assert_eq!("abc", template_replace("a$0b$0c", &[""]));
    assert_eq!("abcde", template_replace("a$0c$1e", &["b", "d"]));
    println!("It works!");
}

Upvotes: 3

Shepmaster
Shepmaster

Reputation: 430681

I would use a regex

use regex::Regex; // 1.1.0

fn example(s: &str, vals: &[&str]) -> String {
    let r = Regex::new(r#"\$(\d+)"#).unwrap();

    let mut start = 0;
    let mut new = String::new();

    for caps in r.captures_iter(s) {
        let m = caps.get(0).expect("Regex group 0 missing");
        let d = caps.get(1).expect("Regex group 1 missing");
        let d: usize = d.as_str().parse().expect("Could not parse index");

        // Copy non-placeholder
        new.push_str(&s[start..m.start()]);
        // Copy placeholder
        new.push_str(&vals[d]);

        start = m.end()
    }

    // Copy non-placeholder
    new.push_str(&s[start..]);

    new
}

fn main() {
    assert_eq!("ab", example("$0$1", &["a", "b"]));
    assert_eq!("$1b", example("$0$1", &["$1", "b"]));
    assert_eq!("moo", example("moo", &[]));
    assert_eq!("abc", example("a$0b$0c", &[""]));
}

See also:

Upvotes: 2

Related Questions