Okay, w .Net i C # wszystkie ciągi są kodowane jako UTF-16LE . A string
jest przechowywany jako sekwencja znaków. Każdy char
hermetyzuje pamięć 2 bajtów lub 16 bitów.
To, co widzimy „na papierze lub ekranie” jako pojedyncza litera, znak, glif, symbol lub znak interpunkcyjny, można traktować jako pojedynczy element tekstowy. Jak opisano w załączniku nr 29 do standardu Unicode, SEGMENTACJA TEKSTU UNICODE , każdy element tekstowy jest reprezentowany przez jeden lub więcej punktów kodowych. Pełną listę kodów można znaleźć tutaj .
Każdy punkt kodowy musi zostać zakodowany w postaci binarnej w celu wewnętrznej reprezentacji przez komputer. Jak wspomniano, każdy char
przechowuje 2 bajty. Punkty kodowe na lub poniżej U+FFFF
mogą być przechowywane w jednym char
. Powyższe punkty kodowe U+FFFF
są przechowywane jako para zastępcza, przy użyciu dwóch znaków reprezentujących pojedynczy punkt kodowy.
Biorąc pod uwagę to, co teraz wiemy, że możemy wydedukować, element tekstowy może być przechowywany jako jeden char
, jako para zastępcza dwóch znaków lub, jeśli element tekstowy jest reprezentowany przez wiele punktów kodowych, pewna kombinacja pojedynczych znaków i par zastępczych. Jakby to nie było wystarczająco skomplikowane, niektóre elementy tekstowe mogą być reprezentowane przez różne kombinacje punktów kodowych, jak opisano w Załączniku nr 15 do normy Unicode, FORMY NORMALIZACJI UNICODE .
Interludium
Tak więc ciągi, które wyglądają tak samo po wyrenderowaniu, mogą w rzeczywistości składać się z innej kombinacji znaków. Porządkowe (bajt po bajcie) porównanie dwóch takich ciągów wykryłoby różnicę, może to być nieoczekiwane lub niepożądane.
Możesz ponownie zakodować ciągi .Net. aby używali tego samego formularza normalizacji. Po znormalizowaniu dwa ciągi z tymi samymi elementami tekstowymi zostaną zakodowane w ten sam sposób. Aby to zrobić, użyj funkcji string.Normalize . Pamiętaj jednak, że niektóre różne elementy tekstowe wyglądają podobnie do siebie. : -s
Więc co to wszystko oznacza w odniesieniu do pytania? Element tekstowy '𠈓'
jest reprezentowany przez pojedyncze rozszerzenie ujednoliconych ideogramów U + 20213 cjk b . Oznacza to, że nie może być zakodowany jako pojedynczy char
i musi być zakodowany jako para zastępcza, przy użyciu dwóch znaków. Dlatego string b
jest o jeden char
dłużej string a
.
Jeśli potrzebujesz rzetelnie (patrz zastrzeżenie) policzyć liczbę elementów tekstowych w a string
, powinieneś użyć takiej
System.Globalization.StringInfo
klasy.
using System.Globalization;
string a = "abc";
string b = "A𠈓C";
Console.WriteLine("Length a = {0}", new StringInfo(a).LengthInTextElements);
Console.WriteLine("Length b = {0}", new StringInfo(b).LengthInTextElements);
dając wyjście,
"Length a = 3"
"Length b = 3"
zgodnie z oczekiwaniami.
Caveat
Implementacja .Net segmentacji tekstu Unicode w klasach StringInfo
i TextElementEnumerator
powinna być ogólnie użyteczna i, w większości przypadków, przyniesie odpowiedź, której oczekuje wywołanie. Jednak, jak stwierdzono w Załączniku nr 29 standardu Unicode, „Cel dopasowania percepcji użytkownika nie zawsze może zostać dokładnie osiągnięty, ponieważ sam tekst nie zawsze zawiera wystarczającą ilość informacji, aby jednoznacznie określić granice”.