// sample-unicode-bom-crlf.rs: non-ASCII text, saved with a UTF-8 byte // order mark and Windows (CRLF) line endings. // Free sample from 99helpers.com/file-types/rs // // rustc skips the byte order mark and treats CRLF like LF, so this file // compiles and prints the same output as an LF copy without a BOM. // Run it: rustc --edition 2024 sample-unicode-bom-crlf.rs && ./sample-unicode-bom-crlf // 1. Identifiers may use non-ASCII letters (since Rust 1.53). const GRÜẞE: &str = "Grüße aus Köln"; fn main() { // 2. A `str` is UTF-8. `len()` counts bytes, `chars().count()` counts // Unicode scalar values; they differ for anything beyond ASCII. let samples = [ "plain ASCII", GRÜẞE, "Ελληνικά", "日本語のテキスト", "مرحبا بالعالم", "emoji 🦀✨", ]; for text in samples { println!( "{:>2} bytes {:>2} chars {text}", text.len(), text.chars().count() ); } // 3. A multi-line string literal. The file's CRLF line breaks are read // as LF, so this string contains "\n" and no "\r". let poem = "first line second line"; assert!(!poem.contains('\r')); println!("{poem:?}"); // 4. Escapes: \u{...} names a character by its code point. let crab = '\u{1F980}'; println!( "{crab} is U+{:04X}, {} bytes in UTF-8", crab as u32, crab.len_utf8() ); // 5. Slicing a string must land on a character boundary. // `&GRÜẞE[..3]` would take "G", "r" and the first of the two bytes // of "ü", and panic at run time, so check with is_char_boundary. let cut = (0..=3) .rev() .find(|&i| GRÜẞE.is_char_boundary(i)) .unwrap_or(0); println!("first {cut} bytes: {:?}", &GRÜẞE[..cut]); }