Чому це так заплутано?
Давайте розберемо це, рядок за рядком
let s1 = "foobar";
Ми створили буквальний рядок, кодований в UTF-8 . UTF-8 дозволяє кодувати 1,114,112 кодові точки з Unicode в манері, досить компактні , якщо ви приїхали з регіонів світу , що типи в основному символів знайдені в ASCII , стандарт , створений в 1963 році UTF-8 є змінною довжиною кодування, що означає, що одна кодова точка може займати від 1 до 4 байт . Коротші кодування зарезервовані для ASCII, але багато кандзі займають 3 байти в UTF-8 .
let mut v: Vec<char> = s1.chars().collect();
Це створює вектор char
акторів. Символ - це 32-бітове число, яке безпосередньо відображається в кодовій точці. Якщо ми починали з тексту лише для ASCII, ми збільшили вимоги до пам'яті в чотири рази. Якщо у нас була купа персонажів з астрального плану , то, можливо, ми не використовували набагато більше.
v[0] = v[0].to_uppercase().nth(0).unwrap();
Це захоплює першу точкову точку і просить перетворити її на верхній регістр. На жаль для тих з нас, хто виріс, розмовляючи англійською, не завжди існує просте індивідуальне відображення "малої літери" у "великої букви" . Примітка: ми називаємо їх великими та малими літерами, тому що одна коробка листів була над другою коробкою листів у той день .
Цей код викликає паніку, коли кодова точка не має відповідного варіанта верхнього регістру. Я не впевнений, чи існують вони насправді. Це також може семантично вийти з ладу, коли кодова точка має варіант верхнього регістру, який має кілька символів, наприклад німецький ß
. Зауважте, що ß насправді ніколи не може бути написано великими літерами у Реальному світі, це лише той приклад, який я завжди можу пам’ятати та шукати. Починаючи з 29.06.2017 року, фактично офіційні правила написання німецької мови оновлено таким чином, що і "ẞ", і "SS" є дійсними великими літерами !
let s2: String = v.into_iter().collect();
Тут ми перетворюємо символи назад в UTF-8 і вимагаємо нового розподілу для їх зберігання, оскільки вихідна змінна зберігалася в постійній пам'яті, щоб не забирати пам'ять під час виконання.
let s3 = &s2;
І тепер ми беремо посилання на це String
.
Це проста проблема
На жаль, це неправда. Можливо, нам слід намагатись навернути світ на есперанто ?
Я припускаю, що char::to_uppercase
вже правильно обробляє Unicode.
Так, я, звичайно, сподіваюся. На жаль, Unicode недостатній у всіх випадках. Завдяки huon за вказівку на турецьку I , де як версії верхнього ( İ ), так і нижнього регістру ( i ) мають крапку. Тобто, немає один капіталізації листи i
; це також залежить від мови вихідного тексту.
навіщо потрібні всі перетворення типів даних?
Оскільки типи даних, з якими ви працюєте, важливі, коли вас турбує правильність та продуктивність. A char
- це 32 біти, а рядок кодується UTF-8. Це різні речі.
індексація може повернути багатобайтовий символ Unicode
Тут може бути якась невідповідна термінологія. A char
- це багатобайтовий символ Unicode.
Нарізання рядка можливо, якщо ви переходите за байтами, але стандартна бібліотека буде панікувати, якщо ви не знаходитесь на межі символів.
Однією з причин того, що індексація рядка для отримання символу так і не було реалізовано, є те, що стільки людей зловживають рядками, як масиви символів ASCII. Індексація рядка для встановлення символу ніколи не може бути ефективною - вам доведеться замінити 1-4 байти значенням, яке також становить 1-4 байта, в результаті чого решта рядка досить сильно відскакує.
to_uppercase
може повернути символ великої літери
Як вже згадувалося вище, ß
це один символ, який після написання великих літер стає двома символами .
Рішення
Див. Також відповідь trentcl, яка містить лише прописні символи ASCII.
Оригінал
Якби мені довелося написати код, це виглядало б так:
fn some_kind_of_uppercase_first_letter(s: &str) -> String {
let mut c = s.chars();
match c.next() {
None => String::new(),
Some(f) => f.to_uppercase().chain(c).collect(),
}
}
fn main() {
println!("{}", some_kind_of_uppercase_first_letter("joe"));
println!("{}", some_kind_of_uppercase_first_letter("jill"));
println!("{}", some_kind_of_uppercase_first_letter("von Hagen"));
println!("{}", some_kind_of_uppercase_first_letter("ß"));
}
Але я б, мабуть, шукав великі регістри чи юнікод на crates.io і дозволяв комусь розумнішим за мене обробляти.
Покращена
Говорячи про "когось розумнішого за мене", Веедрак зазначає, що, ймовірно, ефективніше перетворити ітератор назад у фрагмент після доступу до перших великих кодових точок. Це дозволяє отримати memcpy
решту байтів.
fn some_kind_of_uppercase_first_letter(s: &str) -> String {
let mut c = s.chars();
match c.next() {
None => String::new(),
Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
}
}
ß
коли їх тлумачать як німецьку. Підказка: це не один персонаж. Навіть постановка проблеми може бути складною. Наприклад, неправильно писати великі літери першого символу прізвищаvon Hagen
. Це все аспект життя у світовому світі, в якому тисячі років існували різні культури з різними практиками, і ми намагаємось розбити все це на 8 бітів і 2 рядки коду.