How to convert a slice with many zeros in the end to &str or String?

I have a slice with many zeros in the end.
I just want to get the valid &str, and trim zeros in the end.
But the following code can not impl it.
For example:

let data: [u8; 256] = [
            68, 58, 92, 111, 112, 116, 84, 101, 110, 99, 101, 110, 116, 92, 87, 101, 67, 104, 97,
            116, 0, 0, 110, 0, 116, 0, 92, 0, 87, 0, 101, 0, 67, 0, 104, 0, 97, 0, 116, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        ];
let path = String::from_utf8_lossy(&data[..]);
let path = path.as_ref();
// !!! the length is still 256
println!("path {}, {}", path, path.len());

Is there any other solution or method to impl it?

1 Like

Why would this trim trailing zeros? You never trim anything in this code. Did you forget a call to .trim_end_matches('\0')?

6 Likes

This would be the simplest solution I could think of:

fn main() {
    let data: [u8; 256] = [
        68, 58, 92, 111, 112, 116, 84, 101, 110, 99, 101, 110, 116, 92, 87, 101, 67, 104, 97, 116,
        0, 0, 110, 0, 116, 0, 92, 0, 87, 0, 101, 0, 67, 0, 104, 0, 97, 0, 116, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    ];
    let mut bytes = data
        .into_iter()
        .rev()
        .skip_while(|&byte| byte == 0)
        .collect::<Vec<_>>();
    bytes.reverse();
    let string = String::from_utf8_lossy(&bytes);
    dbg!(string);
}

(Rust Playground)

It first removes the trailing zeroes, collects the result in a new Vec and then uses from_utf8_lossy like in your example.

1 Like

if you are looking for similar functionality of strlen() in C, then you use CStr::from_byte_until_null(), which will search for the first NUL and give you an &CStr slice, and then you use CStr::to_str() (or CStr::to_string_lossy()) to validate its encoding is utf8 and get a rust &str slice (or a sanitized utf8 String).

1 Like

Thanks. I am newer for rust. Starting is difficult for me.

Thanks.
This may be a better solution.

In case it wasn't clear, '\0' (NUL) is a valid UTF8 byte, and thus your internal NULs will still be present in the resulting String (from_utf8_lossy does not remove nor convert them).

In your example they look like one separator NUL followed by UTF16. If that is so you'll need something more complicated to properly convert the input.

2 Likes