• Как записать разные классы в одну переменную?

    zagayevskiy
    @zagayevskiy
    Android developer at Yandex
    В Exp метод надо пометить virtual
    Ответ написан
    Комментировать
  • Как превратить то что вернет WM_CHAR в юникод?

    @Mercury13
    Программист на «си с крестами» и не только
    Recardo_Recoly,
    Понятно.
    1. Лучше использовать WM_UNICHAR, он работает и с кодами более 65535. Поддерживается как минимум WinXP.
    2. Как превратить кодовую позицию в UTF-8, есть много вариантов. Сейчас найду свой.

    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,
    };
    
    void str::putCpNe (char*& p, unsigned long aCp)
    {
        if (aCp <= U8_2BYTE_MAX) {  // 1 or 2 bytes, the most frequent case
            if (aCp <= U8_1BYTE_MAX) {  // 1 byte
                *(p++) = static_cast<char>(aCp);
            } else { // 2 bytes
                *(p++) = static_cast<char>((aCp >> 6)   | 0xC0);
                *(p++) = static_cast<char>((aCp & 0x3F) | 0x80);
            }
        } else {  // 3 or 4 bytes
            if (aCp <= U8_3BYTE_MAX) {  // 3 bytes
                *(p++) = static_cast<char>( (aCp >> 12)        | 0xE0);
                *(p++) = static_cast<char>(((aCp >> 6) & 0x3F) | 0x80);
                *(p++) = static_cast<char>( (aCp       & 0x3F) | 0x80);
            } else {    // 4 bytes
                *(p++) = static_cast<char>(((aCp >> 18) & 0x07) | 0xF0);
                *(p++) = static_cast<char>(((aCp >> 12) & 0x3F) | 0x80);
                *(p++) = static_cast<char>(((aCp >> 6)  & 0x3F) | 0x80);
                *(p++) = static_cast<char>( (aCp        & 0x3F) | 0x80);
            }
        }
    }
    
    void str::appendCp(std::string & s, unsigned long aCp)
    {
        char c[5];
        char* end = c;
        putCpNe(end, aCp);
        s.append(c, end);
    }

    Слово Cp у меня означает code point, кодовая позиция Юникода. Ne — no error-checking, без проверки кодовых позиций на корректность.

    В Си++ есть и штатные функции преобразования кодовых позиций Юникода в UTF-8 и UTF-16. Но страшны, как чёрт, и половина из них в C++17 deprecated :(

    И последнее, что я хочу сказать.
    Вы путаете две вещи: Юникод и его кодовые позиции, и форматы записи юникодных строк UTF-8 и UTF-16. Соотношение «один символ Юникода — один char» только в UTF-32!
    Ответ написан
    33 комментария
  • Как в С++ из INT сделать string16?

    @Mercury13
    Программист на «си с крестами» и не только
    UTF-8 — это многобайтовая кодировка и у неё нет кодов. Так что считаем, что имеем дело с кодами Юникода.
    Это только кусок моей мини-библиотеки, так что…

    Шаблон использовался, чтобы автоматически специализировать под нужную длину wchar_t, реально есть версии под 1 и 2.
    namespace str{
    
    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,
    };
    
    template <int Len>
    void putCpNeT (wchar_t*& p, unsigned long aCp);
    
    ///  Puts a code-point in wchar_t encoding, w/o error-checking
    ///  @param [in,out]  p     position to put to
    ///  @param [in]      aCp   code-point, surely valid
    inline void putCpNe (wchar_t*& p, unsigned long aCp)
        { putCpNeT<sizeof(wchar_t)>(p, aCp); }
    
    } // namespace str
    
    template <>
    void str::putCpNeT<2> (wchar_t*& p, unsigned long aCp)
    {
        if (aCp < U16_2WORD_MIN) {  // 1 word
            *(p++) = static_cast<wchar_t>(aCp);
        } else if (aCp <= U16_2WORD_MAX) {    // 2 words
            aCp -= U16_2WORD_MIN;
            // Hi word
            const wchar_t lo10 = aCp & 0x3FF;
            const wchar_t hi10 = aCp >> 10;
            *(p++) = static_cast<wchar_t>(0xD800 | hi10);
            *(p++) = static_cast<wchar_t>(0xDC00 | lo10);
        }
    }
    
    void str::appendCp(std::wstring& s, unsigned long aCp)
    {
        wchar_t c[5];
        wchar_t* end = c;
        putCpNe(end, aCp);
        s.append(c, end);
    }
    Ответ написан
    Комментировать