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

    @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, считываем слово, не смещая каретки. Если слово не верхний суррогатный символ — херня. В противном случае смещаем каретку и собираем номер кодовой позиции.
    Ответ написан
    Комментировать