Skip to content

String::from_utf16

String methods · Strings

Level: reference · for working programmers

One line: Decodes a &[u16] of UTF-16 code units into a String, or fails — the way back from Windows, Java and JavaScript text.

pub fn from_utf16(v: &[u16]) -> Result<String, FromUtf16Error>

Stable since 1.0.0.

The input is u16 code units, not bytes, and not characters: anything outside the Basic Multilingual Plane arrives as a surrogate pair of two units. This joins them back into one char.

It fails on an unpaired surrogate — a high surrogate with no low one after it. That is not merely theoretical: JavaScript and Windows both permit strings containing them, so text arriving from those worlds can be unrepresentable in Rust, where a String is well-formed UTF-8 by definition. from_utf16_lossy replaces them instead.

When you have bytes rather than u16s, the endianness has to come from somewhere: use from_utf16le or from_utf16be.

Example

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

fn main() {
    let units: Vec<u16> = "hi 👋".encode_utf16().collect();
    println!("{units:?}");
    println!("{:?}", String::from_utf16(&units));

    // A surrogate pair is two units for one char.
    println!("{} units, {} chars", units.len(), "hi 👋".chars().count());

    // An unpaired surrogate is an error, not a character.
    let lone = [0xD83D];
    println!("{:?}", String::from_utf16(&lone).is_err());
    println!("{:?}", String::from_utf16_lossy(&lone));

    // Round trip.
    let text = "héllo 👋";
    let wide: Vec<u16> = text.encode_utf16().collect();
    println!("{}", String::from_utf16(&wide).unwrap() == text);
}

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

[104, 105, 32, 55357, 56395]
Ok("hi 👋")
5 units, 4 chars
true
"�"
true

See also

String::from_utf16 in the standard library ↗

Po polsku

Wejściem są jednostki kodowe u16 — nie bajty i nie znaki — a polszczyzna akurat tę różnicę skutecznie ukrywa: całe nasze „ą ć ę ł ń ó ś ź ż” mieści się w podstawowej płaszczyźnie (BMP), gdzie jedna jednostka to dokładnie jeden znak, więc złudzenie „u16 = char” trzyma się aż do pierwszego emoji. Wtedy pęka: "hi 👋" to 5 jednostek, ale 4 znaki, bo 👋 przyjeżdża jako para surogatów (surrogate pair), którą ta funkcja skleja z powrotem w jeden char. Błędem kończy się wyłącznie niesparowany surogat — Windows i JavaScript dopuszczają takie łańcuchy, a Rustowy String z definicji nie, więc tekst z tamtych światów bywa po prostu niereprezentowalny; wtedy sięgnij po from_utf16_lossy. Jeśli masz surowe bajty zamiast u16, kolejność bajtów musi skądś pochodzić — do tego są from_utf16le i from_utf16be.

Szukaj po polsku: kodowanie UTF-16 · para surogatów · jednostka kodowa · rust String::from_utf16 · rust unpaired surrogate