なぜそんなに複雑なのですか?
行ごとに分解してみましょう
let s1 = "foobar";
UTF-8でエンコードされたリテラル文字列を作成しました。UTF-8を使用すると、1963年に作成された標準であるASCIIで主に文字を入力する世界の地域から来た場合、Unicodeの1,114,112コードポイントをかなりコンパクトな方法でエンコードできます。UTF -8は可変長です。エンコーディング。これは、単一のコードポイントが1〜4バイトかかる可能性があることを意味します。短いエンコーディングはASCII用に予約されていますが、多くの漢字はUTF-8で3バイトを使用します。
let mut v: Vec<char> = s1.chars().collect();
これにより、char
アクターのベクトルが作成されます。文字は、コードポイントに直接マップされる32ビットの数値です。ASCIIのみのテキストから始めた場合、メモリ要件は4倍になりました。アストラル界のキャラクターがたくさんいる場合は、それほど多くは使用していない可能性があります。
v[0] = v[0].to_uppercase().nth(0).unwrap();
これにより、最初のコードポイントが取得され、大文字のバリアントに変換されるように要求されます。英語を話すように育った私たちにとって残念なことに、「小さな文字」から「大きな文字」への単純な1対1のマッピングが常にあるとは限りません。補足:当時、1つの文字ボックスが他の文字ボックスの上にあったため、大文字と小文字を使用します。
コードポイントに対応する大文字のバリアントがない場合、このコードはパニックになります。実際、それらが存在するかどうかはわかりません。また、コードポイントに、ドイツ語などの複数の文字を含む大文字のバリアントがある場合、意味的に失敗する可能性がありますß
。実世界では、ßが実際に大文字になることは決してないことに注意してください。これは、私が常に覚えて検索できる単なる例です。2017-06-29の時点で、実際、ドイツ語のスペルの公式ルールが更新され、「ẞ」と「SS」の両方が有効な大文字になりました。
let s2: String = v.into_iter().collect();
ここでは、文字をUTF-8に変換し直し、実行時にメモリを占有しないように元の変数が定数メモリに格納されていたため、それらを格納するための新しい割り当てが必要です。
let s3 = &s2;
そして今、私たちはそれへの参照を取りString
ます。
それは単純な問題です
残念ながら、これは真実ではありません。おそらく、私たちは世界をエスペラントに変えるよう努力すべきでしょうか?
私はchar::to_uppercase
すでにUnicodeを適切に処理していると思います。
はい、私は確かにそう願っています。残念ながら、Unicodeはすべての場合に十分ではありません。トルコ語のIを指摘してくれたhuonに感謝します。ここでは、大文字(İ)と小文字(i)の両方のバージョンにドットが付いています。それは何もありません、ある1つの文字の正しい総額は、ソーステキストのロケールにも依存します。i
なぜすべてのデータ型変換が必要なのですか?
正確性とパフォーマンスが心配な場合は、使用するデータ型が重要であるためです。Achar
は32ビットで、文字列はUTF-8でエンコードされています。それらは異なるものです。
インデックス作成は、マルチバイトのUnicode文字を返す可能性があります
ここにいくつかの不一致の用語があるかもしれません。Achar
はマルチバイトのUnicode文字です。
バイトごとに移動する場合は文字列をスライスできますが、文字の境界にいない場合は標準ライブラリがパニックになります。
文字を取得するために文字列にインデックスを付けることが実装されなかった理由の1つは、非常に多くの人々が文字列をASCII文字の配列として誤用しているためです。文字列にインデックスを付けて文字を設定するのは決して効率的ではありません。1〜4バイトを1〜4バイトの値に置き換える必要があり、文字列の残りの部分がかなりバウンドします。
to_uppercase
大文字を返す可能性があります
上記のように、ß
は1文字で、大文字にすると2文字になります。
ソリューション
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
、残りのバイトの1つが可能になります。
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行のコードに押しつぶそうとしています。