Гаразд, у .Net та C # всі рядки кодуються як UTF-16LE . А string
зберігається як послідовність символів. Кожна char
капсула зберігає 2 байти або 16 біт.
Те, що ми бачимо «на папері чи екрані» як окрему букву, символ, гліф, символ або розділовий знак, можна розглядати як єдиний текстовий елемент. Як описано в стандартному додатку Unicode № 29 СЕГМЕНТАЦІЯ ТЕКСТУ UNICODE , кожен текстовий елемент представлений однією або кількома кодовими точками. Вичерпний список кодів можна знайти тут .
Кожну кодову точку потрібно закодувати у двійковий код для внутрішнього представлення комп'ютером. Як зазначено, кожен char
зберігає 2 байти. Кодові точки в і нижче U+FFFF
можна зберігати в одній char
. Кодові точки вище U+FFFF
зберігаються у вигляді сурогатної пари, використовуючи дві символи для представлення однієї кодової точки.
З огляду на те, що ми знаємо, що ми можемо зробити, текстовий елемент може бути збережений як один char
, як сурогатний пара з двох знаків або, якщо текстовий елемент представлений кількома кодовими точками, деякою комбінацією одиничних знаків і сурогатних пар. Як би це не було досить складним, деякі текстові елементи можуть бути представлені різними комбінаціями точок коду, як описано в, стандартному додатку Unicode, № 15, НОРМАЛІЗАЦІЙНИЙ ФОРМ UNICODE .
Інтермедія
Таким чином, рядки, які виглядають однаково при рендерингу, насправді можуть складатися з різної комбінації символів. Порядкове (байт у байті) порівняння двох таких рядків виявило б різницю, це може бути несподівано або небажано.
Ви можете перекодувати рядки .Net. щоб вони використовували ту саму Форму нормалізації. Після нормалізації два рядки з однаковими текстовими елементами будуть закодовані однаково. Для цього використовуйте функцію string.Normalize . Однак пам’ятайте, деякі різні текстові елементи схожі між собою. : -s
Отже, що це все означає стосовно питання? Текстовий елемент '𠈓'
представлений єдиним розширенням уніфікованих ідеографів cjk U + 20213 cjk b . Це означає, що він не може бути кодований як єдиний char
і повинен бути кодований як сурогатний пара, використовуючи дві символи. Ось чому string b
один char
довший string a
.
Якщо вам потрібно надійно (див. Застереження) підрахувати кількість текстових елементів у a, string
ви повинні використовувати такий
System.Globalization.StringInfo
клас.
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);
даючи вихід,
"Length a = 3"
"Length b = 3"
як і очікувалося.
Caveat
Реалізація тексту тексту Unicode у класах StringInfo
та TextElementEnumerator
класах має бути загалом корисною та в більшості випадків дасть відповідь, яку очікує абонент. Однак, як зазначено у стандартному додатку Unicode, доданий №29, "мета співставлення сприйняття користувачів не завжди може бути точно досягнута, оскільки сам по собі текст не завжди містить достатньо інформації для однозначного визначення меж".