String 为什么将字符串的第一个字母大写会如此复杂?
我想把aString 为什么将字符串的第一个字母大写会如此复杂?,string,rust,uppercase,String,Rust,Uppercase,我想把a&str的第一个字母大写。这是一个简单的问题,我希望有一个简单的解决办法。直觉告诉我这样做: let mut s = "foobar"; s[0] = s[0].to_uppercase(); 但是&strs不能像这样被索引。我唯一能做到这一点的方法似乎过于复杂。我将&str转换为迭代器,将迭代器转换为向量,向量中的第一项大写,这将创建一个迭代器,我将其索引,创建一个选项,我将其展开以给出大写的第一个字母。然后我把向量转换成迭代器,我把它转换成一个字符串,我把它转换成&str let
&str
的第一个字母大写。这是一个简单的问题,我希望有一个简单的解决办法。直觉告诉我这样做:
let mut s = "foobar";
s[0] = s[0].to_uppercase();
但是&str
s不能像这样被索引。我唯一能做到这一点的方法似乎过于复杂。我将&str
转换为迭代器,将迭代器转换为向量,向量中的第一项大写,这将创建一个迭代器,我将其索引,创建一个选项
,我将其展开以给出大写的第一个字母。然后我把向量转换成迭代器,我把它转换成一个字符串,我把它转换成&str
let s1 = "foobar";
let mut v: Vec<char> = s1.chars().collect();
v[0] = v[0].to_uppercase().nth(0).unwrap();
let s2: String = v.into_iter().collect();
let s3 = &s2;
let s1=“foobar”;
让mut v:Vec=s1.chars().collect();
v[0]=v[0]。to_大写();
设s2:String=v.into_iter().collect();
设s3=&s2;
有比这更简单的方法吗?如果有,是什么?如果不是,为什么防锈设计是这样的
为什么这么复杂?
让我们一行一行地把它分解
let s1 = "foobar";
我们已经创建了一个编码为的文本字符串。UTF-8允许我们以一种非常紧凑的方式对的1114112进行编码,如果您来自世界上的一个地区,输入的字符主要是1963年创建的标准中的字符。UTF-8是一种可变长度编码,这意味着单个代码点可能会发生变化。较短的编码是为ASCII保留的,但是
这将获取第一个代码点并请求将其转换为大写变量。不幸的是,对于我们这些从小说英语的人来说,这是一个错误。旁注:我们称之为大写和小写
当代码点没有相应的大写变量时,此代码将死机。实际上,我不确定这些是否存在。当一个代码点有一个包含多个字符的大写变体(如德语ß
)时,它也可能在语义上失败。请注意,在现实世界中,ß可能永远不会大写,这正是我可以始终记住并搜索的示例。事实上,截至2017年6月29日,德语拼写的官方规则已经更新,因此
在这里,我们将字符转换回UTF-8,并需要新的分配来存储它们,因为原始变量存储在常量内存中,以便在运行时不占用内存
let s3 = &s2;
现在我们引用这个字符串
这是一个简单的问题
不幸的是,事实并非如此。也许我们应该努力使世界转变为
我认为char::to_大写已经正确地处理了Unicode
是的,我当然希望如此。不幸的是,Unicode在所有情况下都是不够的。
多亏了,大写(İ)和小写(i)版本都有一个点。也就是说,字母i
没有一个适当的大写字母;这也取决于源文本的格式
为什么需要所有数据类型转换
因为当您担心正确性和性能时,使用的数据类型非常重要。字符为32位,字符串为UTF-8编码。它们是不同的东西
索引可以返回多字节的Unicode字符
这里可能有一些不匹配的术语。char
是多字节Unicode字符
如果逐字节执行,则可以对字符串进行切片,但如果不在字符边界上,则标准库将死机
为字符串建立索引以获取字符从未实现的原因之一是,许多人将字符串误用为ASCII字符数组。为字符串编制索引以设置字符永远不会有效率-您必须能够将1-4字节替换为1-4字节的值,从而导致字符串的其余部分大量跳转
to_uppercase
可能返回大写字符
如上所述,ß
是一个单独的字符,当大写时,会变成两个字符
解决
另请参见哪些仅使用大写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(),
}
}
fn某种类型的大写字母首字母(s:&str)->字符串{
设mut c=s.chars();
匹配c.next(){
None=>String::new(),
Some(f)=>f.to_大写().collect::()+c.as_str(),
}
}
有比这更简单的方法吗?如果有,是什么?如果不是,为什么防锈设计是这样的
嗯,是和否。正如另一个答案所指出的,你的代码是不正确的,如果你给它类似的东西,它会惊慌失措བོད་སྐད་ལ་. 因此,使用Rust的标准库执行此操作比您最初想象的还要困难
然而,Rust的设计目的是鼓励代码重用,并使引入库变得容易。因此,将字符串大写的惯用方法实际上非常容易接受:
extern crate inflector;
use inflector::Inflector;
let capitalized = "some string".to_title_case();
如果您能够将输入限制为仅限ASCII字符串,则不会特别复杂
由于Rust 1.23,str
有一个make_ascii_uppercase
方法(在较旧的Rust版本中,可通过AsciiExt
trait获得)。这意味着您可以相对轻松地仅使用大写ASCII字符串片段:
fn make_ascii_titlecase(s: &mut str) {
if let Some(r) = s.get_mut(0..1) {
r.make_ascii_uppercase();
}
}
这将把“taylor”
变成“taylor”
,但不会把“édouard”
变成“édouard”
。()
请谨慎使用。这里有一个版本比@Shepmaster的改进版稍慢一些,但也更惯用:
fn首字母大写(s:&str)->字符串{
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(),
}
}
extern crate inflector;
use inflector::Inflector;
let capitalized = "some string".to_title_case();
fn make_ascii_titlecase(s: &mut str) {
if let Some(r) = s.get_mut(0..1) {
r.make_ascii_uppercase();
}
}
fn str_cap(s: &str) -> String {
format!("{}{}", (&s[..1].to_string()).to_uppercase(), &s[1..])
}
fn str_cap(s: &str) -> String {
format!("{}{}", s.chars().next().unwrap().to_uppercase(),
s.chars().skip(1).collect::<String>())
}