Хорошо, в .Net и C # все строки кодируются как UTF-16LE . A string
хранится как последовательность символов. Каждый char
инкапсулирует хранилище в 2 байта или 16 бит.
То, что мы видим «на бумаге или экране» как одну букву, символ, глиф, символ или знак пунктуации, можно рассматривать как отдельный элемент текста. Как описано в Стандартном приложении Unicode № 29 СЕГМЕНТАЦИЯ ТЕКСТА ЮНИКОДА , каждый текстовый элемент представлен одной или несколькими кодовыми точками. Исчерпывающий список кодов можно найти здесь .
Каждую кодовую точку необходимо закодировать в двоичный файл для внутреннего представления компьютером. Как указано, каждый char
хранит 2 байта. Кодовые точки на или ниже U+FFFF
могут быть сохранены в одном char
. Вышеуказанные кодовые точки U+FFFF
хранятся в виде суррогатной пары с использованием двух символов для представления единой кодовой точки.
Учитывая то, что мы теперь знаем, что мы можем сделать вывод, текстовый элемент может быть сохранен как один char
, как суррогатная пара из двух символов или, если текстовый элемент представлен несколькими кодовыми точками, как некоторая комбинация отдельных символов и суррогатных пар. Как будто это не было достаточно сложно, некоторые текстовые элементы могут быть представлены различными комбинациями кодовых точек, как описано в Стандартном приложении № 15 к Unicode, ФОРМЫ НОРМАЛИЗАЦИИ ЮНИКОДА .
интерлюдия
Таким образом, строки, которые выглядят одинаково при визуализации, могут фактически состоять из другой комбинации символов. Порядковое (побайтное) сравнение двух таких строк обнаружило бы разницу, это может быть неожиданным или нежелательным.
Вы можете перекодировать строки .Net. чтобы они использовали одну и ту же форму нормализации. После нормализации две строки с одинаковыми текстовыми элементами будут кодироваться одинаково. Для этого используйте функцию string.Normalize . Однако помните, что некоторые различные текстовые элементы похожи друг на друга. : -s
Итак, что все это значит в отношении вопроса? Текстовый элемент '𠈓'
представлен единым расширением унифицированных идеограмм кодовой точки 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"
как и ожидалось.
Предостережение
Реализация .Net в Unicode Text Сегментации в StringInfo
и TextElementEnumerator
классах должна быть в целом полезной и, в большинстве случаев, даст ответ , что предпологает абонент. Однако, как указано в Приложении № 29 к стандарту Unicode, «цель сопоставления восприятия пользователя не всегда может быть достигнута именно потому, что один только текст не всегда содержит достаточно информации, чтобы однозначно определить границы».