Dieser Code:
string a = "abc";
string b = "A𠈓C";
Console.WriteLine("Length a = {0}", a.Length);
Console.WriteLine("Length b = {0}", b.Length);
Ausgänge:
Length a = 3
Length b = 4
Warum? Das einzige, was ich mir vorstellen kann, ist, dass das chinesische Schriftzeichen 2 Bytes lang ist und dass die .Length
Methode die Anzahl der Bytes zurückgibt.
𠈓
Zeichens ist 131603, und da Zeichen vorzeichenlose Bytes sind, bedeutet dies, dass Sie diesen Wert in 2 statt in 4 Zeichen erreichen können (maximaler vorzeichenloser 16-Bit-Wert beträgt 65535 (oder 65536 Variationen) und die Verwendung von 2 Zeichen zur Darstellung ermöglicht für eine maximale Anzahl von Variationen von nicht 65536 * 2 (131072), sondern 65536 * 65536 Variationen (4.294.967.296, effektiv ein 32-Bit-Wert)Antworten:
Alle anderen geben die oberflächliche Antwort, aber es gibt auch eine tiefere Begründung: Die Anzahl der "Zeichen" ist eine schwer zu definierende Frage und kann überraschend teuer zu berechnen sein, während eine Längeneigenschaft schnell sein sollte.
Warum ist es schwer zu definieren? Nun, es gibt ein paar Optionen und keine ist wirklich gültiger als die andere:
Die Anzahl der Codeeinheiten (Bytes oder andere Datenblöcke mit fester Größe; C # und Windows verwenden normalerweise UTF-16, sodass die Anzahl der Zwei-Byte-Teile zurückgegeben wird) ist sicherlich relevant, da der Computer die Daten in dieser Form noch verarbeiten muss für viele Zwecke (das Schreiben in eine Datei kümmert sich beispielsweise eher um Bytes als um Zeichen)
Die Anzahl der Unicode-Codepunkte ist ziemlich einfach zu berechnen (obwohl O (n), weil Sie die Zeichenfolge nach Ersatzpaaren durchsuchen müssen) und kann für einen Texteditor von Bedeutung sein. Sie entspricht jedoch nicht der Anzahl der Zeichen auf dem Bildschirm gedruckt (Grapheme genannt). Beispielsweise können einige Buchstaben mit Akzent in zwei Formen dargestellt werden: ein einzelner Codepunkt oder zwei miteinander gepaarte Punkte, einer für den Buchstaben und einer mit der Aufschrift "Fügen Sie meinem Partnerbrief einen Akzent hinzu". Wäre das Paar zwei Zeichen oder eins? Sie können Zeichenfolgen normalisieren, um dies zu unterstützen, aber nicht alle gültigen Buchstaben haben eine einzige Codepunktdarstellung.
Selbst die Anzahl der Grapheme entspricht nicht der Länge einer gedruckten Zeichenfolge, was unter anderem von der Schriftart abhängt. Da einige Zeichen in vielen Schriftarten (Kerning) mit einer gewissen Überlappung gedruckt werden, wird die Länge einer Zeichenfolge auf dem Bildschirm angezeigt ist sowieso nicht unbedingt gleich der Summe der Länge der Grapheme!
Einige Unicode-Punkte sind nicht einmal Zeichen im herkömmlichen Sinne, sondern eine Art Kontrollmarker. Wie eine Bytereihenfolge-Markierung oder eine Anzeige von rechts nach links. Zählen diese?
Kurz gesagt, die Länge eines Strings ist tatsächlich eine lächerlich komplexe Frage, und die Berechnung kann sowohl CPU-Zeit als auch Datentabellen in Anspruch nehmen.
Was ist der Sinn? Warum sind diese Metriken wichtig? Nun, nur Sie können das für Ihren Fall beantworten, aber ich persönlich finde, dass sie im Allgemeinen irrelevant sind. Die Einschränkung der Dateneingabe erfolgt logischerweise eher durch Byte-Limits, da diese ohnehin übertragen oder gespeichert werden müssen. Das Begrenzen der Anzeigegröße wird besser von der Anzeigeseiten-Software durchgeführt. Wenn Sie 100 Pixel für die Nachricht haben, hängt die Anzahl der Zeichen von der Schriftart usw. ab, was der Datenschicht-Software ohnehin nicht bekannt ist. Angesichts der Komplexität des Unicode-Standards werden Sie wahrscheinlich ohnehin Fehler an den Randfällen haben, wenn Sie etwas anderes ausprobieren.
Es ist also eine schwierige Frage, die nicht häufig für allgemeine Zwecke verwendet wird. Die Anzahl der Codeeinheiten ist trivial zu berechnen - es ist nur die Länge des zugrunde liegenden Datenarrays - und in der Regel die aussagekräftigste / nützlichste mit einer einfachen Definition.
Das ist der Grund, warum
b
die Länge4
über die oberflächliche Erklärung von "weil die Dokumentation dies sagt" hinausgeht.quelle
Length
es veraltet sein sollte, um die Analogie mit Arrays beizubehalten.Aus der Dokumentation der
String.Length
Immobilie:quelle
String b
), da es die UTF-16-Darstellung in char-Arrays verwendet. Es ist ein 4-Byte-Zeichen in UTF-8.Dein Charakter bei Index 1 in
"A𠈓C"
ist ein SurrogatePairSie können diesen Code ausprobieren und er wird zurückgegeben
True
Char.IsSurrogatePair-Methode (String, Int32)
Dies wird in der Eigenschaft String.Length näher erläutert :
quelle
Wie die anderen Antworten gezeigt haben, werden sie, selbst wenn 3 sichtbare Zeichen vorhanden sind, mit 4
char
Objekten dargestellt. DeshalbLength
ist das 4 und nicht 3.MSDN gibt das an
Wenn Sie jedoch wirklich die Anzahl der "Textelemente" und nicht die Anzahl der
Char
Objekte wissen möchten, können Sie dieStringInfo
Klasse verwenden.Sie können auch jedes Textelement wie folgt auflisten
Bei Verwendung
foreach
der Zeichenfolge wird der mittlere "Buchstabe" in zweichar
Objekte aufgeteilt, und das gedruckte Ergebnis entspricht nicht der Zeichenfolge.quelle
Dies liegt daran, dass die
Length
Eigenschaft die Anzahl der Zeichenobjekte und nicht die Anzahl der Unicode-Zeichen zurückgibt . In Ihrem Fall wird eines der Unicode-Zeichen durch mehr als ein Zeichenobjekt (SurrogatePair) dargestellt.quelle
Wie andere sagten, ist es nicht die Anzahl der Zeichen in der Zeichenfolge, sondern die Anzahl der Char-Objekte. Das Zeichen 𠈓 ist der Codepunkt U + 20213. Da der Wert außerhalb des Bereichs des 16-Bit-Zeichentyps liegt, wird er in UTF-16 als Ersatzpaar codiert
D840 DE13
.Der Weg, um die Länge in Zeichen zu erhalten, wurde in den anderen Antworten erwähnt. Es sollte jedoch mit Vorsicht verwendet werden, da es viele Möglichkeiten gibt, ein Zeichen in Unicode darzustellen. "à" kann 1 zusammengesetztes Zeichen oder 2 Zeichen (a + diakritische Zeichen) sein. Eine Normalisierung kann erforderlich sein, wie im Fall von Twitter .
Sie sollten dies lesen. Das absolute Minimum, das jeder Softwareentwickler unbedingt
über Unicode und Zeichensätze wissen muss (keine Ausreden!)
quelle
Dies liegt daran, dass
length()
nur Unicode-Codepunkte verwendet werden, die nicht größer als sindU+FFFF
. Dieser Satz von Codepunkten wird als BMP ( Basic Multilingual Plane ) bezeichnet und verwendet nur 2 Byte.Unicode-Codepunkte außerhalb von
BMP
werden in UTF-16 mit 4-Byte-Ersatzpaaren dargestellt.Verwenden Sie, um die Anzahl der Zeichen (3) korrekt zu zählen
StringInfo
quelle
Okay, in .Net und C # sind alle Zeichenfolgen als UTF-16LE codiert . A
string
wird als Folge von Zeichen gespeichert. Jedeschar
kapselt die Speicherung von 2 Bytes oder 16 Bits.Was wir "auf Papier oder Bildschirm" als einen einzelnen Buchstaben, ein Zeichen, eine Glyphe, ein Symbol oder ein Interpunktionszeichen sehen, kann als ein einzelnes Textelement betrachtet werden. Wie in Unicode Standard Annex # 29 UNICODE TEXT SEGMENTATION beschrieben , wird jedes Textelement durch einen oder mehrere Codepunkte dargestellt. Eine vollständige Liste der Codes finden Sie hier .
Jeder Codepunkt muss für die interne Darstellung durch einen Computer binär codiert werden. Wie angegeben,
char
speichert jeder 2 Bytes. Codepunkte an oder unterU+FFFF
können in einem einzigen gespeichert werdenchar
. Die obigenU+FFFF
Codepunkte werden als Ersatzpaar gespeichert, wobei zwei Zeichen verwendet werden, um einen einzelnen Codepunkt darzustellen.Wenn wir wissen, was wir jetzt ableiten können, kann ein Textelement als eines
char
, als Ersatzpaar aus zwei Zeichen oder, wenn das Textelement durch mehrere Codepunkte dargestellt wird, als Kombination aus einzelnen Zeichen und Ersatzpaaren gespeichert werden. Als ob das nicht kompliziert genug wäre, können einige Textelemente durch verschiedene Kombinationen von Codepunkten dargestellt werden, wie in Unicode Standard Annex # 15, UNICODE NORMALIZATION FORMS beschrieben .Zwischenspiel
Zeichenfolgen, die beim Rendern gleich aussehen, können also aus einer anderen Kombination von Zeichen bestehen. Ein ordinaler (Byte für Byte) Vergleich zweier solcher Zeichenfolgen würde einen Unterschied feststellen. Dies kann unerwartet oder unerwünscht sein.
Sie können .NET-Zeichenfolgen neu codieren. so dass sie das gleiche Normalisierungsformular verwenden. Nach der Normalisierung werden zwei Zeichenfolgen mit denselben Textelementen auf dieselbe Weise codiert. Verwenden Sie dazu die Funktion string.Normalize . Denken Sie jedoch daran, dass einige verschiedene Textelemente einander ähnlich sehen. : -s
Was bedeutet das alles in Bezug auf die Frage? Das
'𠈓'
Textelement wird durch die einzelne Code Point U + 20213 cjk Unified Ideographs-Erweiterung b dargestellt . Dies bedeutet, dass es nicht als einzelneschar
Zeichen codiert werden kann und als Ersatzpaar mit zwei Zeichen codiert werden muss. Deshalbstring b
ist manchar
länger sostring a
.Wenn Sie die Anzahl der Textelemente in a zuverlässig zählen müssen (siehe Einschränkung)
string
, sollten Sie dieSystem.Globalization.StringInfo
Klasse wie folgt verwenden.die Ausgabe geben,
wie erwartet.
Vorbehalt
Die .NET-Implementierung der Unicode-Textsegmentierung in den Klassen
StringInfo
undTextElementEnumerator
sollte im Allgemeinen nützlich sein und in den meisten Fällen eine Antwort liefern, die der Aufrufer erwartet. Wie in Unicode Standard Annex # 29 angegeben, "kann das Ziel der Übereinstimmung der Benutzerwahrnehmungen nicht immer genau erreicht werden, da der Text allein nicht immer genügend Informationen enthält, um Grenzen eindeutig zu bestimmen."quelle