Skip to content

str::from_utf8

str methods · Strings

Level: reference · for working programmers

One line: Validates a &[u8] and returns Result<&str, Utf8Error> — the checked way in, borrowing rather than copying.

pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error>

Stable since 1.87.0. Usable in a const context.

An associated function, so it is str::from_utf8(bytes). It scans the bytes once and either hands back a &str over the same memory or reports where the scan failed.

Utf8Error is unusually informative: valid_up_to() gives the number of bytes that were fine, and error_len() distinguishes an invalid sequence (Some(n)) from an input that simply stops mid-character (None). That second case is what you get reading a stream in fixed-size chunks, and it is a signal to wait for more bytes rather than to reject the input.

For lossy decoding — replace bad sequences with U+FFFD and carry on — use String::from_utf8_lossy.

const fn, so a byte literal can be validated at compile time.

Example

str_from_utf8.rs in full — pasted here by tools/run_examples.py from the file CI compiles and runs.

// The invalid byte arrays below are the point of the example, so the
// lint that spots them is turned off rather than worked around.
#![allow(invalid_from_utf8)]

fn main() {
    let good = [104, 105];
    println!("{:?}", str::from_utf8(&good));

    // Invalid sequence: where it failed, and how long the bad run is.
    let bad = [104, 0xff, 105];
    match str::from_utf8(&bad) {
        Ok(s) => println!("{s:?}"),
        Err(e) => println!("valid_up_to {} error_len {:?}", e.valid_up_to(), e.error_len()),
    }

    // Truncated input: error_len is None, meaning "incomplete", not "invalid".
    let cut = "é".as_bytes();
    println!("{:?}", str::from_utf8(&cut[..1]).unwrap_err().error_len());

    // Borrowed, not copied: the same bytes, reinterpreted.
    let owned = vec![104, 105];
    let view = str::from_utf8(&owned).unwrap();
    println!("{view:?} from a {}-byte buffer", owned.len());

    // const validation.
    const BYTES: &[u8] = b"compiled";
    const TEXT: &str = match str::from_utf8(BYTES) { Ok(s) => s, Err(_) => "" };
    println!("{TEXT:?}");
}

Verified output of str_from_utf8.rs — regenerated by tools/run_examples.py, never hand-typed.

Ok("hi")
valid_up_to 1 error_len Some(1)
None
"hi" from a 2-byte buffer
"compiled"

See also

str::from_utf8 in the standard library ↗

Po polsku

str::from_utf8 sprawdza tablicę bajtów i zwraca Result<&str, Utf8Error> — bez kopiowania, bo w razie powodzenia dostajesz wycinek łańcucha (string slice) nad tymi samymi bajtami, tylko zinterpretowanymi jako tekst. Dla polskiego tekstu najciekawsze jest to, co niesie Utf8Error: każda litera z ogonkiem lub kreską zajmuje w UTF-8 dwa bajty, więc czytając strumień porcjami o stałym rozmiarze prędzej czy później przetniesz „ż” na pół — i wtedy error_len() zwraca None, co znaczy „dane się urwały, dosyłaj resztę”, a nie „dane są zepsute” (to jest Some(n), plus valid_up_to() mówiące, ile bajtów było dobrych). Pomylenie tych dwóch przypadków to klasyczny sposób na odrzucenie całkiem poprawnego wejścia; jeśli zamiast błędu wolisz podstawić znak zastępczy U+FFFD i liczyć dalej, to już zadanie dla String::from_utf8_lossy.

Szukaj po polsku: kodowanie UTF-8 · polskie znaki diakrytyczne w UTF-8 · walidacja bajtów · rust str::from_utf8 Utf8Error · rust error_len valid_up_to