Tại sao nó lại phức tạp như vậy?
Hãy chia nhỏ nó, từng dòng một
let s1 = "foobar";
Chúng tôi đã tạo một chuỗi ký tự được mã hóa bằng UTF-8 . UTF-8 cho phép chúng tôi mã hóa 1.114.112 điểm mã của Unicode theo cách khá nhỏ gọn nếu bạn đến từ một khu vực trên thế giới nhập hầu hết các ký tự được tìm thấy trong ASCII , một tiêu chuẩn được tạo ra vào năm 1963. UTF-8 là một độ dài thay đổi mã hóa, có nghĩa là một điểm mã có thể chiếm từ 1 đến 4 byte . Các mã hóa ngắn hơn được dành riêng cho ASCII, nhưng nhiều chữ Kanji chiếm 3 byte trong UTF-8 .
let mut v: Vec<char> = s1.chars().collect();
Điều này tạo ra một vector của bộ truyền động char
. Một ký tự là một số 32 bit ánh xạ trực tiếp đến một điểm mã. Nếu chúng tôi bắt đầu với văn bản chỉ ASCII, chúng tôi đã tăng gấp bốn lần yêu cầu bộ nhớ của mình. Nếu chúng ta có một loạt các nhân vật từ cõi không gian , thì có lẽ chúng ta đã không sử dụng nhiều hơn thế nữa.
v[0] = v[0].to_uppercase().nth(0).unwrap();
Thao tác này lấy điểm mã đầu tiên và yêu cầu nó được chuyển đổi thành một biến thể viết hoa. Thật không may cho những người trong chúng ta, những người lớn lên nói tiếng Anh, không phải lúc nào cũng có một ánh xạ đơn giản giữa "chữ cái nhỏ" với "chữ cái lớn" . Lưu ý bên lề: chúng ta gọi chúng là chữ hoa và chữ thường bởi vì một hộp chữ cái nằm trên hộp chữ cái kia vào ngày xưa .
Mã này sẽ hoảng loạn khi một điểm mã không có biến thể viết hoa tương ứng. Tôi không chắc liệu chúng có tồn tại hay không. Nó cũng có thể không thành công về mặt ngữ nghĩa khi một điểm mã có biến thể viết hoa có nhiều ký tự, chẳng hạn như tiếng Đức ß
. Lưu ý rằng ß có thể không bao giờ thực sự được viết hoa trong Thế giới thực, đây là ví dụ duy nhất mà tôi luôn có thể nhớ và tìm kiếm. Kể từ ngày 26 tháng 6 năm 2017, trên thực tế, các quy tắc chính thức của chính tả tiếng Đức đã được cập nhật để cả "ẞ" và "SS" đều là cách viết hoa hợp lệ !
let s2: String = v.into_iter().collect();
Ở đây chúng tôi chuyển đổi các ký tự trở lại UTF-8 và yêu cầu một cấp phát mới để lưu trữ chúng, vì biến ban đầu được lưu trữ trong bộ nhớ không đổi để không chiếm bộ nhớ trong thời gian chạy.
let s3 = &s2;
Và bây giờ chúng ta tham khảo điều đó String
.
Đó là một vấn đề đơn giản
Thật không may, điều này là không đúng sự thật. Có lẽ chúng ta nên cố gắng chuyển đổi thế giới sang Esperanto ?
Tôi cho rằng char::to_uppercase
đã xử lý đúng Unicode.
Vâng, tôi chắc chắn hy vọng như vậy. Thật không may, Unicode không đủ trong mọi trường hợp. Cảm ơn huon đã chỉ ra chữ I của Thổ Nhĩ Kỳ , trong đó cả phiên bản viết hoa ( İ ) và viết thường ( i ) đều có dấu chấm. Đó là, không có một cách viết hoa thích hợp của chữ cái i
; nó cũng phụ thuộc vào ngôn ngữ của văn bản nguồn.
tại sao lại cần tất cả các chuyển đổi kiểu dữ liệu?
Bởi vì các loại dữ liệu bạn đang làm việc rất quan trọng khi bạn lo lắng về tính đúng đắn và hiệu suất. A char
là 32 bit và một chuỗi được mã hóa UTF-8. Chúng là những thứ khác nhau.
lập chỉ mục có thể trả về một ký tự Unicode, nhiều byte
Có thể có một số thuật ngữ không khớp ở đây. A char
là một ký tự Unicode nhiều byte.
Có thể cắt một chuỗi nếu bạn chuyển từng byte, nhưng thư viện tiêu chuẩn sẽ hoảng sợ nếu bạn không ở trên ranh giới ký tự.
Một trong những lý do khiến việc lập chỉ mục một chuỗi để lấy một ký tự không bao giờ được thực hiện là vì có quá nhiều người sử dụng sai chuỗi làm mảng ký tự ASCII. Lập chỉ mục một chuỗi để đặt một ký tự không bao giờ có thể hiệu quả - bạn phải có thể thay thế 1-4 byte bằng một giá trị cũng là 1-4 byte, khiến phần còn lại của chuỗi bị trả lại khá nhiều.
to_uppercase
có thể trả về một ký tự chữ hoa
Như đã nói ở trên, ß
là một ký tự đơn lẻ mà khi viết hoa sẽ trở thành hai ký tự .
Các giải pháp
Xem thêm câu trả lời của trentcl chỉ viết hoa các ký tự ASCII.
Nguyên
Nếu tôi phải viết mã, nó sẽ giống như sau:
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("ß"));
}
Nhưng có lẽ tôi sẽ tìm kiếm chữ hoa hoặc mã unicode trên crates.io và để ai đó thông minh hơn tôi xử lý.
Cải tiến
Nói về "ai đó thông minh hơn tôi", Veedrac chỉ ra rằng có thể hiệu quả hơn khi chuyển đổi trình lặp lại thành một lát sau khi các điểm mã vốn đầu tiên được truy cập. Điều này cho phép memcpy
phần còn lại của các byte.
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(),
}
}
ß
khi được hiểu là tiếng Đức. Gợi ý: nó không phải là một ký tự đơn lẻ. Ngay cả câu lệnh vấn đề cũng có thể phức tạp. Ví dụ, sẽ không đúng nếu viết hoa ký tự đầu tiên của họvon Hagen
. Đây là tất cả khía cạnh của cuộc sống trong một thế giới toàn cầu đã có hàng nghìn năm văn hóa khác nhau với các tập tục khác nhau và chúng tôi đang cố gắng thu gọn tất cả những thứ đó thành 8 bit và 2 dòng mã.