Home > OS >  Reverse string using .as_bytes()
Reverse string using .as_bytes()

Time:12-04

I'm trying to reverse a string. I use the solution of this post and it works.

But I would like to try with bytes instead of grapheme clusters as shown below:

pub fn reverse2(input: &str) -> String {
    let s: String = input
        .as_bytes()
        .iter()
        .rev()
        .collect();
    return s;
}

Unfortunately, I can't run the function collect() after rev(). I don't know which method to use. How would you do it ?

CodePudding user response:

As you explicitly ask about not using chars(), you have to restrict yourself to ASCII strings.

pub fn reverse2(input: &str) -> String {
    // Reversing on byte-level only works with ASCII strings.
    assert!(input.is_ascii());

    let reversed_bytes: Vec<u8> = input.as_bytes().iter().copied().rev().collect();
    let reversed_string = unsafe {
        // SAFETY: This is guaranteed to be a valid UTF8 string, because:
        // - the input string is a valid ASCII string
        // - a reversed ASCII string is still a valid ASCII string
        // - an ASCII string is a valid UTF8 string
        String::from_utf8_unchecked(reversed_bytes)
    };

    return reversed_string;
}

You can also use the checked version, if you don't like the unsafe, but it comes with a little bit of overhead:

pub fn reverse2(input: &str) -> String {
    // Reversing on byte-level only works with ASCII strings.
    assert!(input.is_ascii());

    let reversed_bytes: Vec<u8> = input.as_bytes().iter().copied().rev().collect();
    let reversed_string = String::from_utf8(reversed_bytes).unwrap();

    return reversed_string;
}

Optimization:

Checking is_ascii() is some overhead. It is not strictly required, however.

UTF-8 has one special property: every non-ASCII byte is valued 128 and above. So technically it is enough to just simply filter out all values equal to or above 128:

pub fn reverse2(input: &str) -> String {
    let reversed_bytes: Vec<u8> = input
        .as_bytes()
        .iter()
        .rev()
        .map(|&val| {
            if val < 128 {
                val
            } else {
                0x1a // replacement char
            }
        })
        .collect();

    let reversed_string = unsafe {
        // SAFETY: This is guaranteed to be a valid UTF8 string, because:
        // - `reversed_bytes` is guaranteed to be an ASCII string
        // - an ASCII string is a valid UTF8 string
        String::from_utf8_unchecked(reversed_bytes)
    };

    return reversed_string;
}

fn main() {
    let s = "abcde           
  • Related