为什么这么复杂?
让我们逐行将其分解
let s1 = "foobar";
我们创建了一个以UTF-8编码的文字字符串。UTF-8使我们能够以非常紧凑的方式对Unicode的1,114,112个编码点进行编码,如果您来自世界某个地区,该地区键入的大部分字符都是ASCII(一种1963年创建的标准)中的字符。UTF-8是可变长度的编码,这意味着单个代码点可能需要1到4个字节。较短的编码保留给ASCII,但是许多汉字在UTF-8中占用3个字节。
let mut v: Vec<char> = s1.chars().collect();
这创建了char
参与者的载体。字符是直接映射到代码点的32位数字。如果我们从仅ASCII文本开始,那么我们的内存需求就增加了三倍。如果我们从星体平面中获得了一堆字符,那么也许我们没有使用太多了。
v[0] = v[0].to_uppercase().nth(0).unwrap();
这将获取第一个代码点,并请求将其转换为大写形式。不幸的是,对于那些长大说英语的人来说,并不总是简单地将“小字母”映射为“大字母”。旁注:我们称它们为大写和小写,因为在一天中,一个字母框位于另一字母框上方。
当代码点没有相应的大写字母变体时,此代码将出现恐慌。我不确定这些是否确实存在。当代码点具有包含多个字符的大写变体(例如German)时,在语义上也会失败ß
。请注意,在《真实世界》中,ß可能永远不会大写,这是我永远记得并寻找的唯一示例。截至2017年6月29日,事实上,德语拼写的官方规则已经这样更新了两个“ẞ”和“SS”是有效的市值!
let s2: String = v.into_iter().collect();
在这里,我们将字符转换回UTF-8,并需要进行新分配以将其存储在其中,因为原始变量存储在常量内存中,以便在运行时不占用内存。
let s3 = &s2;
现在我们参考一下String
。
这是一个简单的问题
不幸的是,事实并非如此。也许我们应该努力将世界转变为世界语?
我认为char::to_uppercase
已经正确处理了Unicode。
是的,我当然希望如此。不幸的是,在所有情况下,Unicode都是不够的。由于胡恩您指出了土耳其我,其中两个上(İ)和较低的情况下,(我)的版本有一个点。也就是说,没有一个适当的大写字母i
;它也取决于源文本的语言环境。
为什么需要所有数据类型转换?
因为当您担心正确性和性能时,正在使用的数据类型很重要。Achar
是32位,字符串是UTF-8编码的。他们是不同的东西。
索引可能返回一个多字节Unicode字符
这里可能有一些术语不匹配。Achar
是一个多字节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上搜索大写或unicode,然后让比我聪明的人来处理它。
已改善
在谈到“比我聪明的人”时,Veedrac指出,在访问第一个大写代码点之后,将迭代器转换回片可能更有效。这允许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行代码。