의 첫 글자를 대문자로 쓰고 싶습니다 &str
. 간단한 문제이고 간단한 해결책을 원합니다. 직감은 나에게 다음과 같은 것을하라고 말한다.
let mut s = "foobar";
s[0] = s[0].to_uppercase();
그러나 &str
s는 이와 같이 인덱싱 할 수 없습니다. 내가 할 수 있었던 유일한 방법은 지나치게 복잡해 보입니다. 나는 변환 &str
작성, 반복자,로 I 인덱스를 생성하는 벡터의 벡터, 대문자로 첫 번째 항목을 반복자를 변환, 반복자에 Option
내가 나에게 대문자가 첫 번째 문자를주고 풀다 어느. 그런 다음 벡터를 반복자 String
로 변환하여으로 변환하고 &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;
이것보다 더 쉬운 방법이 있습니까? 그렇다면 무엇입니까? 그렇지 않다면 Rust가 이런 방식으로 디자인 된 이유는 무엇입니까?
답변
왜 그렇게 복잡합니까?
한 줄씩 나눠 보자
let s1 = "foobar";
UTF-8로 인코딩 된 리터럴 문자열을 만들었습니다 . UTF-8을 사용하면 유니 코드 의 1,114,112 코드 포인트 를 매우 간결한 방식으로 인코딩 할 수 있습니다 . 1963 년에 생성 된 표준 인 ASCII 로 대부분의 문자를 입력하는 세계 지역에서 왔을 때입니다 . UTF-8은 가변 길이입니다. 이는 단일 코드 포인트가 1에서 4 바이트까지 걸릴 수 있음을 의미합니다 . 더 짧은 인코딩은 ASCII 용으로 예약되어 있지만 많은 Kanji는 UTF-8에서 3 바이트를 사용 합니다.
let mut v: Vec<char> = s1.chars().collect();
이것은 char
행위자 의 벡터를 만듭니다 . 문자는 코드 포인트에 직접 매핑되는 32 비트 숫자입니다. ASCII 전용 텍스트로 시작했다면 메모리 요구 사항이 4 배가되었습니다. 만약 우리가 아스트랄 계 의 캐릭터들을 가지고 있다면, 우리는 그다지 많이 사용하지 않았을 것입니다.
v[0] = v[0].to_uppercase().nth(0).unwrap();
이것은 첫 번째 코드 포인트를 잡고 대문자 변형으로 변환하도록 요청합니다. 유감스럽게도 영어로 자란 우리에게는 “소문자”를 “큰 문자”에 대한 간단한 일대일 매핑이 항상있는 것은 아닙니다 . 참고 : 과거에는 한 상자의 글자가 다른 글자 상자보다 위에 있었기 때문에 대문자와 소문자라고 부릅니다 .
이 코드는 코드 포인트에 해당하는 대문자 변형이 없을 때 패닉 상태가됩니다. 실제로 존재하는지 확실하지 않습니다. 또한 코드 포인트에 German과 같이 여러 문자가있는 대문자 변형이있는 경우 의미 상 실패 할 수 있습니다 ß
. ß는 The Real World에서 실제로 대문자로 표기되지 않을 수 있습니다. 이것은 제가 항상 기억하고 검색 할 수있는 유일한 예입니다. 2017년 6월 29일로, 사실, 독일어 맞춤법의 공식 규칙이 이렇게 업데이트되었는지 모두 “ẞ”과 “SS”는 유효한 총액은 !
let s2: String = v.into_iter().collect();
여기서는 문자를 다시 UTF-8로 변환하고 런타임에 메모리를 차지하지 않도록 원래 변수가 상수 메모리에 저장되었으므로이를 저장할 새 할당이 필요합니다.
let s3 = &s2;
그리고 이제 우리는 그것을 참조합니다 String
.
간단한 문제
불행히도 이것은 사실이 아닙니다. 아마도 우리는 세상을 에스페란토 로 바꾸려고 노력해야 할까요?
나는
char::to_uppercase
이미 유니 코드를 제대로 처리한다고 생각한다.
네, 확실히 그러길 바랍니다. 불행히도 모든 경우에 유니 코드만으로는 충분하지 않습니다. 대문자 ( İ )와 소문자 ( i ) 버전 모두에 점이 있는 터키어 I 를 지적 해 주신 huon에게 감사드립니다 . 즉 더 없다,있다 한 편지의 적절한 총액 ; 소스 텍스트 의 로케일 에 따라 다릅니다 .i
모든 데이터 유형 변환이 필요한 이유는 무엇입니까?
작업중인 데이터 유형은 정확성과 성능이 걱정 될 때 중요하기 때문입니다. A char
는 32 비트이고 문자열은 UTF-8로 인코딩됩니다. 그들은 다른 것들입니다.
인덱싱은 멀티 바이트 유니 코드 문자를 반환 할 수 있습니다.
여기에 일치하지 않는 용어가있을 수 있습니다. A char
는 멀티 바이트 유니 코드 문자입니다.
바이트 단위로 이동하면 문자열을 슬라이싱 할 수 있지만 문자 경계에 있지 않으면 표준 라이브러리가 패닉 상태가됩니다.
문자를 얻기 위해 문자열 인덱싱이 구현되지 않은 이유 중 하나는 많은 사람들이 문자열을 ASCII 문자 배열로 오용하기 때문입니다. 문자 를 설정 하기 위해 문자열을 인덱싱하는 것은 결코 효율적일 수 없습니다. 1-4 바이트를 1-4 바이트 값으로 대체 할 수 있어야 나머지 문자열이 상당히 많이 바운스됩니다.
to_uppercase
대문자를 반환 할 수 있습니다.
위에서 언급 ß
했듯이은 대문자로 입력하면 두 문자 가되는 단일 문자입니다 .
솔루션
ASCII 문자 만 대문자로하는 trentcl의 답변 도 참조하십시오 .
실물
코드를 작성해야한다면 다음과 같이 보일 것입니다.
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 에서 대문자 또는 유니 코드 를 검색하고 나보다 똑똑한 사람이 처리하도록 할 것입니다.
향상
“나보다 똑똑한 사람”에 대해 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(),
}
}
답변
이것보다 더 쉬운 방법이 있습니까? 그렇다면 무엇입니까? 그렇지 않다면 Rust가 이런 방식으로 디자인 된 이유는 무엇입니까?
글쎄, 예 그리고 아니오. 귀하의 코드는 다른 답변에서 지적했듯이 정확하지 않으며 བོད་ སྐད་ ལ་와 같은 것을 제공하면 당황합니다. 따라서 Rust의 표준 라이브러리로 이것을하는 것은 처음에 생각했던 것보다 훨씬 더 어렵습니다.
그러나 Rust는 코드 재사용을 장려하고 라이브러리를 쉽게 가져올 수 있도록 설계되었습니다. 따라서 문자열을 대문자로 표기하는 관용적 방법은 실제로 매우 맛있습니다.
extern crate inflector;
use inflector::Inflector;
let capitalized = "some string".to_title_case();
답변
입력을 ASCII 전용 문자열로 제한 할 수 있다면 특별히 복잡하지 않습니다.
녹 1.23 이후, str
이 make_ascii_uppercase
방법을 (오래된 녹 버전에서, 그것은을 통해 사용할 수있었습니다 AsciiExt
특성). 이것은 상대적으로 쉽게 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"
. ( 놀이터 )
주의해서 사용하십시오.
답변
이것이 제가이 문제를 해결 한 방법입니다. 대문자로 변환하기 전에 self가 ASCII가 아닌지 확인해야했습니다.
trait TitleCase {
fn title(&self) -> String;
}
impl TitleCase for &str {
fn title(&self) -> String {
if !self.is_ascii() || self.is_empty() {
return String::from(*self);
}
let (head, tail) = self.split_at(1);
head.to_uppercase() + tail
}
}
pub fn main() {
println!("{}", "bruno".title());
println!("{}", "b".title());
println!("{}", "?".title());
println!("{}", "ß".title());
println!("{}", "".title());
println!("{}", "བོད་སྐད་ལ".title());
}
산출
Bruno
B
?
ß
བོད་སྐད་ལ
답변
@Shepmaster의 개선 된 버전보다 약간 느리지 만 더 관용적 인 버전이 있습니다 .
fn capitalize_first(s: &str) -> String {
let mut chars = s.chars();
chars
.next()
.map(|first_letter| first_letter.to_uppercase())
.into_iter()
.flatten()
.chain(chars)
.collect()
}
답변
나는 이렇게했다 :
fn str_cap(s: &str) -> String {
format!("{}{}", (&s[..1].to_string()).to_uppercase(), &s[1..])
}
ASCII 문자열이 아닌 경우 :
fn str_cap(s: &str) -> String {
format!("{}{}", s.chars().next().unwrap().to_uppercase(),
s.chars().skip(1).collect::<String>())
}