Кодирование байтового массива UTF-16 в строковый символ C#. NET - PullRequest
4 голосов
/ 05 апреля 2020

У меня есть байтовый массив, который, я считаю, правильно хранит суррогатную пару в кодировке UTF-16 для символа Юникод ?

Выполнение этого байтового массива через. Net System.Text.Encoding.Unicode.GetString() возвращает непредвиденные результаты.

Фактические результаты: ��

Ожидаемые результаты: ?

Пример кода:

byte[] inputByteArray = new byte[4];
inputByteArray[0] = 0x91;
inputByteArray[1] = 0xDF;
inputByteArray[2] = 0x00;
inputByteArray[3] = 0xD8;

// System.Text.Encoding.Unicode accepts little endian UTF-16
// Least significant byte first within the byte array [0] MSByete in [3]
string str = System.Text.Encoding.Unicode.GetString(inputByteArray);

// This returns �� rather than the excpected symbol: ? 
Console.WriteLine(str);

Подробно о том, как я получил этот конкретный байтовый массив из персонаж: 101

Этот персонаж находится в Дополнительной многоязычной плоскости. Этот символ в Юникоде является 0x10391. Кодированный в суррогатную пару UTF-16, это должно быть:

Минус значение Юникода с 0x10000: val = 0x00391 = (0x10391 - 0x10000)

Высокий суррогат: 0xD800 = ( 0xD800 + (0x00391 >> 10 )) старшие 10 бит

Низкий суррогат: 0xDF91 = (0xDC00 + (0x00391 & 0b_0011_1111_1111)) младшие 10 бит

1 Ответ

5 голосов
/ 05 апреля 2020

Encoding.Unicode является прямым порядком байтов в кодовой единице для UTF-16 . Вам все еще нужно поместить модуль с высоким суррогатным кодом перед модулем с низким суррогатным кодом. Вот пример кода, который работает:

using System;
using System.Text;

class Test
{
    static void Main()
    {
        byte[] data =
        {
            0x00, 0xD8, // High surrogate
            0x91, 0xDF  // Low surrogate
        };
        string text = Encoding.Unicode.GetString(data);
        Console.WriteLine(char.ConvertToUtf32(text, 0)); // 66449
    }
}
...