Warum ist es so verworren?
Lassen Sie es uns Zeile für Zeile aufschlüsseln
let s1 = "foobar";
Wir haben eine Literalzeichenfolge erstellt, die in UTF-8 codiert ist . Mit UTF-8 können wir die 1.114.112 Codepunkte von Unicode auf eine ziemlich kompakte Weise codieren, wenn Sie aus einer Region der Welt stammen, in der hauptsächlich Zeichen eingegeben werden, die in ASCII , einem 1963 erstellten Standard, gefunden wurden. UTF-8 ist eine variable Länge Codierung, was bedeutet, dass ein einzelner Codepunkt 1 bis 4 Bytes benötigen kann . Die kürzeren Codierungen sind für ASCII reserviert, aber viele Kanji benötigen in UTF-8 3 Bytes .
let mut v: Vec<char> = s1.chars().collect();
Dies erzeugt einen Vektor von char
Akteuren. Ein Zeichen ist eine 32-Bit-Zahl, die direkt einem Codepunkt zugeordnet ist. Wenn wir mit Nur-ASCII-Text begonnen haben, haben wir unseren Speicherbedarf vervierfacht. Wenn wir eine Reihe von Charakteren aus der Astralebene hätten , hätten wir vielleicht nicht viel mehr verwendet.
v[0] = v[0].to_uppercase().nth(0).unwrap();
Dadurch wird der erste Codepunkt erfasst und die Konvertierung in eine Großbuchstabenvariante angefordert. Leider gibt es für diejenigen von uns, die mit Englisch aufgewachsen sind, nicht immer eine einfache Eins-zu-Eins-Zuordnung eines "kleinen Buchstabens" zu einem "großen Buchstaben" . Randnotiz: Wir nennen sie Groß- und Kleinbuchstaben, weil sich früher eine Buchstabenschachtel über der anderen Buchstabenschachtel befand .
Dieser Code gerät in Panik, wenn ein Codepunkt keine entsprechende Großbuchstabenvariante hat. Ich bin mir nicht sicher, ob diese tatsächlich existieren. Es kann auch semantisch fehlschlagen, wenn ein Codepunkt eine Großbuchstabenvariante mit mehreren Zeichen enthält, z. B. Deutsch ß
. Beachten Sie, dass ß in der realen Welt möglicherweise nie groß geschrieben wird. Dies ist das einzige Beispiel, an das ich mich immer erinnern und nach dem ich suchen kann. Ab dem 29.06.2017 wurden die offiziellen Regeln der deutschen Rechtschreibung aktualisiert, sodass sowohl "ẞ" als auch "SS" gültige Großschreibung sind !
let s2: String = v.into_iter().collect();
Hier konvertieren wir die Zeichen zurück in UTF-8 und benötigen eine neue Zuordnung, um sie zu speichern, da die ursprüngliche Variable im konstanten Speicher gespeichert wurde, um zur Laufzeit keinen Speicher zu belegen.
let s3 = &s2;
Und jetzt nehmen wir einen Hinweis darauf String
.
Es ist ein einfaches Problem
Dies ist leider nicht wahr. Vielleicht sollten wir uns bemühen, die Welt zum Esperanto zu konvertieren ?
Ich gehe davon aus char::to_uppercase
, dass Unicode bereits richtig gehandhabt wird.
Ja, das hoffe ich sehr. Leider reicht Unicode nicht in allen Fällen aus. Vielen Dank an huon für den Hinweis auf das türkische I , bei dem sowohl die Groß- ( İ ) als auch die Kleinbuchstaben ( i ) einen Punkt haben. Das heißt, es nicht ist eine angemessene Kapitalisierung des Briefes i
; Dies hängt auch vom Gebietsschema des Quelltextes ab.
Warum müssen alle Datentypkonvertierungen durchgeführt werden?
Weil die Datentypen, mit denen Sie arbeiten, wichtig sind, wenn Sie sich um Korrektheit und Leistung sorgen. A char
ist 32-Bit und eine Zeichenfolge ist UTF-8-codiert. Sie sind verschiedene Dinge.
Die Indizierung kann ein Multi-Byte-Unicode-Zeichen zurückgeben
Möglicherweise gibt es hier eine nicht übereinstimmende Terminologie. A char
ist ein Multi-Byte-Unicode-Zeichen.
Das Schneiden einer Zeichenfolge ist möglich, wenn Sie Byte für Byte arbeiten. Die Standardbibliothek gerät jedoch in Panik, wenn Sie sich nicht an einer Zeichengrenze befinden.
Einer der Gründe, warum die Indizierung einer Zeichenfolge zum Abrufen eines Zeichens nie implementiert wurde, ist, dass so viele Benutzer Zeichenfolgen als Arrays von ASCII-Zeichen missbrauchen. Das Indizieren einer Zeichenfolge zum Festlegen eines Zeichens könnte niemals effizient sein - Sie müssten in der Lage sein, 1-4 Bytes durch einen Wert zu ersetzen, der ebenfalls 1-4 Bytes beträgt, was dazu führt, dass der Rest der Zeichenfolge ziemlich viel herumspringt.
to_uppercase
könnte ein Großbuchstaben zurückgeben
Wie oben erwähnt, ß
handelt es sich um ein einzelnes Zeichen, das bei Großschreibung zu zwei Zeichen wird .
Lösungen
Siehe auch die Antwort von trentcl, bei der nur ASCII-Zeichen in Großbuchstaben geschrieben werden.
Original
Wenn ich den Code schreiben müsste, würde er so aussehen:
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("ß"));
}
Aber ich würde wahrscheinlich auf crates.io nach Großbuchstaben oder Unicode suchen und jemanden schlauer als mich damit umgehen lassen.
Verbessert
Veedrac spricht von "jemandem, der schlauer ist als ich" und weist darauf hin, dass es wahrscheinlich effizienter ist, den Iterator nach dem Zugriff auf die ersten Großbuchstaben wieder in ein Slice umzuwandeln. Dies ermöglicht einen memcpy
Rest der Bytes.
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(),
}
}
ß
wenn es als Deutsch interpretiert wird. Hinweis: Es ist kein einzelnes Zeichen. Auch die Problemstellung kann kompliziert sein. Zum Beispiel wäre es unangemessen, das erste Zeichen des Nachnamens groß zu schreibenvon Hagen
. Dies alles ist ein Aspekt des Lebens in einer globalen Welt, in der es seit Tausenden von Jahren unterschiedliche Kulturen mit unterschiedlichen Praktiken gibt, und wir versuchen, all diese in 8 Bit und 2 Codezeilen zusammenzufassen.