3

I want to write a function which takes a mutable string and checks if the first and last character are the " character. If so, those two characters should be replaced with the backtick character `. I've come up with this solution:

fn replace_wrapping_char(s: &mut String) {
    if s.len() > 1 && s.starts_with('"') && s.ends_with('"') {
        unsafe {
            let v = s.as_mut_vec();
            v[0] = '`' as u8;
            *v.last_mut().unwrap() = '`' as u8;
        }
    }
}

This seems to work (yes, '`'.is_ascii() returns true), but it uses unsafe and looks a bit ugly to me.

Is there a safe and concise way to achieve what I want?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Lukas Kalbertodt
  • 79,749
  • 26
  • 255
  • 305
  • https://stackoverflow.com/questions/26544542/modifying-chars-in-a-string-by-index – Josh Lee Mar 28 '17 at 17:28
  • Do you know if the whole string will be ASCII, or is it only guaranteed that the first / last character might be ASCII? – Shepmaster Mar 28 '17 at 19:03
  • @Shepmaster I know nothing about the ascii-ness of the string. If the first/last character are `"`, then they are ascii (obviously...), otherwise no guarantee. – Lukas Kalbertodt Mar 28 '17 at 19:20
  • 1
    I guess what you'd want is if [AsciiExt](https://doc.rust-lang.org/std/ascii/trait.AsciiExt.html) had a `set_ascii_char_at(index, new_char)` which returns a `Result<>` rather than panics if it can't work. But there doesn't seem to be anything like that today. – Chris Emerson Mar 29 '17 at 15:47

1 Answers1

1

Here is a safe, shortened version of that function, although it won't be memory efficient. This will create a copy and reassign the given string, so a pure function prototype returning a new string would probably be more fitting here. It also relies on the fact that the double quote character is 1-byte sized in UTF-8.

fn replace_wrapping_char(s: &mut String) {
    if s.len() > 1 && s.starts_with('"') && s.ends_with('"') {
        *s = format!("`{}`", &s[1 .. s.len()-1])
    }
}

Playground

E_net4
  • 27,810
  • 13
  • 101
  • 139
  • 1
    Noob question, but doesn't this copy the whole string and then re-assign it to `s`? Shouldn't there be a way to do this by just mutating the first and last bytes? – Alec Mar 28 '17 at 16:25
  • @Alec Exactly, this will copy and reassign the string, so I admit this isn't the best solution to the problem. Nevertheless, I'll just keep it here in case someone is ok with a copy. – E_net4 Mar 28 '17 at 16:31
  • @Alec *by just mutating the first and last bytes* — that's what OP's solution does, but it has to be unsafe because the type system can't guarantee that the first/last byte *was* ASCII and *remains* ASCII. – Shepmaster Mar 28 '17 at 19:03