В Юникод , у вас есть кодовые точки .Это 21 бит длиной.Ваш персонаж ?, Mathematical Bold Capital A
, имеет кодовую точку U + 1D400.
В кодировках Unicode у вас есть кодовые единицы .Это естественная единица кодирования: 8-бит для UTF-8 , 16-бит для UTF-16 искоро.Одна или несколько кодовых единиц кодируют одну кодовую точку.
В UTF-16 две кодовые единицы, образующие одну кодовую точку, называются суррогатной парой .Суррогатные пары используются для кодирования любой кодовой точки больше 16 бит, то есть U + 10000 и выше.
Это немного сложно в .NET, так как .NET Char
представляет один код UTF-16.единица, а .NET String
- это набор единиц кода.
Таким образом, ваша кодовая точка ? (U + 1D400) не может уместиться в 16 бит и нуждается в суррогатной паре, то есть в вашей строке двакодовые единицы в нем:
var highUnicodeChar = "?";
char a = highUnicodeChar[0]; // code unit 0xD835
char b = highUnicodeChar[1]; // code unit 0xDC00
То есть, когда вы индексируете строку таким образом, вы фактически получаете только половину суррогатной пары.
Вы можете использовать IsSurrogatePair для проверки суррогатной пары.Например:
string GetFullCodePointAtIndex(string s, int idx) =>
s.Substring(idx, char.IsSurrogatePair(s, idx) ? 2 : 1);
Важно отметить, что кроличья нора переменной кодировки в Unicode не заканчивается в точке кода. кластер графем - это «видимая вещь», которую большинство людей, когда ее спрашивают, в конечном итоге называют «персонажем».Кластер графемы состоит из одной или нескольких кодовых точек: базовый символ и ноль или более комбинирующих символов.Примером комбинирующего символа является умлаут или различные другие украшения / модификаторы, которые вы можете добавить.В этом ответе приведен ужасающий пример того, что могут делать комбинирующие символы.
Чтобы проверить наличие комбинирующего символа, вы можете использовать GetUnicodeCategory , чтобы проверить наличие вмещающей метки,непространственный знак или промежуточный знак.