Is there a counterpart of str::trim_matches()?

I frequently use the function and it works pretty well. However, when I need to do an opposite job and put a string in quotes, I use something like:

format!(r#""{str}""#);

I am curious what do you use for the task?

String::push() might be more efficient, but I would just use format!() and not worry about it.

with push():

fn in_quotes(s: &str) -> String {
    let qs = String::with_capacity(s.len()+2);
    qs.push('"');
    qs.push_str(s);
    qs.push('"');
    qs
}
1 Like

I agree that I wouldn't worry too much about exactly how efficient each respective method is. However, if you're so inclined, here's my naive Godbolt showing the two methods. What's interesting to me is that the naive-seeming format method directly generates much less code, presumably due to the large amount of dyn indirection present in std::fmt. Somebody might run some benchmarks to see how the two compare in practice (as far as microbenchmarks can actually tell you anything).

2 Likes

For the exact job of quoting a string, I tend to just lean on the debug formatter. It tends to be less confusing if any of the escaped characters are required anyway, and it's less ugly in source! But who knows just how much machinery that pulls in from std::fmt, there's a lot of state it could possibly switch on from Formatter

There's probably some code-golf-y options using iterator meetings to make the string building approach prettier without losing performance, it's pretty clever about remembering the sizes of the input to reserve the correct output sizes (it can actually be faster than the equivalent explicit code, because they specialize with unsafe implementations that don't need bound checking etc.)

1 Like

Using a custom trait with unsafe code:

Thank you all for the feedback. Currently I stick with the solution, as simple and efficient:

fn enclose(s: &str, left: &str, right: &str) -> String {
    let mut res = String::with_capacity(s.len() + left.len() + right.len());
    res.push_str(left);
    res.push_str(s);
    res.push_str(right);
    res
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
    let s = "test";
    println!("{}", enclose(s, "\"", "\""));
    println!("{}", enclose(s, "{[", "]}"));
    println!("{}", enclose(s, "<", ">"));
    println!("{}", enclose(s, "'", "'"));
    println!("{}", enclose(s, "«", "»"));
    println!("{}", enclose(s, "❝", "❞"));
    println!("{}", enclose(s, "</", ">"));
    println!("{}", enclose(s, "", ">>>"));
    println!("{}", enclose(&String::new(), "</", ">"));
    Ok(())
}

Result:
"test"
{[test]}

'test'

«test»
❝test❞

test>>>
</>

I think only to create a trait for the job.