@NORMgg

Как декодировать UTF-16 на С++?

Надо сделать декодер кодировки UTF-16 на языке С++ или C. Есть код на Pascal(https://ru.wikipedia.org/wiki/UTF-16), но не могу его понять, так как плохо знаю данный язык.
Код на Pascal:
// В случае успеха возвращаются значения
// в диапазонах $0000..$D7FF и $E000..$10FFFF.
Function ReadUTF16Char: UInt32
    Var Leading:  Word  // Лидирующее (первое) слово.
    Var Trailing: Word  // Последующее (второе) слово.

    Leading = ReadWord();
    If (Leading < $D800) Or (Leading > $DFFF) Then
        Return WordToUInt32(Leading)
    Else If (Leading >= $DC00) Then
        Error("Недопустимая кодовая последовательность.")
    Else
        Var Code: UInt32
        Code = WordToUInt32(Leading And $3FF) Shl 10
        Trailing = ReadWord()
        If ((Trailing < $DC00) Or (Trailing > $DFFF)) Then
            Error("Недопустимая кодовая последовательность.")
        Else
            Code = Code Or WordToUInt32(Trailing And $3FF)
            Return (Code + $10000)
        End If
    End If
End Function
  • Вопрос задан
  • 76 просмотров
Решения вопроса 1
@Mercury13
Программист на «си с крестами» и не только
Это не Паскаль, это типизированный Бейсик.
Вот мой рабочий код — каждый вызов читает одну кодовую позицию, перемещая первый указатель на нужное кол-во слов вперёд. Переведёшь в нужные тебе соглашения по работе? — например, ты можешь читать информацию не из памяти, а из файла или ещё откуда-то.
enum {
    SURROGATE_MIN = 0xD800,
    SURROGATE_MAX = 0xDFFF,
    SURROGATE_LO_MIN = SURROGATE_MIN,
    SURROGATE_HI_MIN = 0xDC00,
    SURROGATE_LO_MAX = SURROGATE_HI_MIN - 1,
    SURROGATE_HI_MAX = SURROGATE_MAX,
    UNICODE_MAX = 0x10FFFF,
    U8_1BYTE_MAX = 0x7F,
    U8_2BYTE_MIN = 0x80,
    U8_2BYTE_MAX = 0x7FF,
    U8_3BYTE_MIN = 0x800,
    U8_3BYTE_MAX = 0xFFFF,
    U8_4BYTE_MIN = 0x10000,
    U8_4BYTE_MAX = UNICODE_MAX,
    U16_1WORD_MAX = 0xFFFF,
    U16_2WORD_MIN = 0x10000,
    U16_2WORD_MAX = UNICODE_MAX,
};

#define CHAR_BOM L'\uFEFF'

#define UNICODE_NONE (0xFFFFFFFFUL)
#define UNICODE_BAD  (0xFFFFFFFEUL)

unsigned long str::getCp(const uint16_t*& aCurr, const uint16_t* aEnd)
{
    if (aCurr == aEnd)
        return UNICODE_NONE;
    unsigned long cp = *(aCurr++);
    if (cp < SURROGATE_HI_MIN) {
        if (cp < SURROGATE_MIN) { // Low BMP char => OK
            return cp;
        } else {  // Leading surrogate
            if (aCurr == aEnd)
                return UNICODE_BAD;
            unsigned long trailing = *aCurr;
            if (trailing < SURROGATE_HI_MIN || trailing > SURROGATE_HI_MAX)
                return UNICODE_BAD;
            ++aCurr;
            return (((cp & 0x3FF) << 10) | (trailing & 0x3FF)) + 0x10000;
        }
    } else {
        if (cp <= SURROGATE_MAX) { // Trailing surrogate
            return UNICODE_BAD;
        } else { // High BMP char => OK
            return cp;
        }
    }
}


Параметры: первый (передан по сцылке) — подвижная «каретка», второй указывает за конец строки.
Возвращает: NONE, если читать больше нечего, BAD, если считал херню, и кодовую позицию — если таковая всё-таки считалась.

Алгоритм: читаем слово. Двумя сравнениями относим его к одному из четырёх диапазонов: 1) нижний диапазон базовой плоскости, 2) нижний суррогатный символ; 3) верхний суррогатный символ; 4) верхний диапазон базовой плоскости. Если 1 или 4, так его и возвращаем, если 3 — видим херню.

Если же 2, считываем слово, не смещая каретки. Если слово не верхний суррогатный символ — херня. В противном случае смещаем каретку и собираем номер кодовой позиции.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы