2016-09-20 11 views
0

Я сейчас пишу собственную функцию DrawTextEx(), которая поддерживает смайлики. Используя эту функцию, обратный вызов вызывается каждый раз, когда в тексте содержится смайлик, предоставляя возможность вызывающему абоненту заменить текстовый сегмент, содержащий смайлик, на изображение. Например, символы Unicode 0x3DD8 0x00DE, найденные в тексте, будут заменены улыбающимся изображением лица во время рисования текста. На самом деле эта функция работает нормально.Преобразование кода смайлика «HTML-объект» в UTF16 (в C++)

Теперь я хочу реализовать библиотеку изображений со стороны абонента. Я получаю текстовый сегмент, такой как 0x3DD8 0x00DE, в моей функции обратного вызова, и моя идея состоит в том, чтобы использовать этот код в качестве ключа на карте, содержащей все комбинации Юникода, каждый из которых связан со структурой, содержащей изображение для рисования. Я нашел хороший пакет на сайте http://emojione.com/developers/. Все пакеты, доступные на этом сайте, содержат несколько имен файлов, это шестнадцатеричный код. Поэтому я могу перебирать файлы, содержащиеся в пакете, и автоматически создавать свою карту.

Однако я обнаружил, что эти коды являются частью другого стандарта и на самом деле представляют собой набор элементов с названием «объект HTML», которые, по-видимому, используются в веб-разработке, как это видно на веб-сайте http://graphemica.com/%F0%9F%98%80. Поэтому, чтобы иметь возможность использовать эти файлы, мне нужно решение для преобразования значений сущности HTML, содержащихся в их именах, в код UTF16. Например, в случае вышеупомянутого улыбающегося лица мне нужно преобразовать код сущности 0x1f600 HTML в код 0x3DD8 0x00DE UTF16.

Подход грубой силы может состоять в том, чтобы написать карту, которая преобразует эти коды, путем добавления каждого из них в моем коде один за другим. Но поскольку стандарт Unicode содержит в наиболее оптимистичном сценарии более 1800 комбинаций для смайликов, я хочу знать, что существует существующее решение, такое как известный API или функция, которые я могу использовать для выполнения этой работы. Или есть известный трюк? (Как, например, "символ + ('а' - 'A')" для преобразования в верхнем регистре полукокса, чтобы понизить)

С уважением

ответ

1

Например, Unicode обугливает 0x3DD8 0x00DE найти в тексте будут заменены улыбающегося изображениями лица

символ U + 1F600 Grinning лицо представлен код единичной последовательности UTF-16 0xD83D, 0xDE00.

(Graphemica поменяв порядок байтов для каждого блока кода супер вводит в заблуждение, игнорировать это.)

Я обнаружил, что эти коды являются частью другого стандарта, и, по сути, набор элементов по имени «HTML-сущность», видимо, используется в веб-разработке.

HTML-код не имеет к этому никакого отношения. Это простые символы Unicode - только те, что находятся за пределами базовой многоязычной плоскости, выше U + FFFF, поэтому для их представления требуется более одного кода кода UTF-16.

HTML-числовые символьные ссылки, такие как 😀 (часто неправильно называемые объектами), являются способом обращения к символам с помощью номера кодовой точки, но escape-строка эффективна только в документе HTML (или XML), и мы не в одном из них.

Итак:

Мне нужно преобразовать код сущности 0x1f600 HTML коду 0x3DD8 0x00DE utf16.

звучит как:

Мне нужно преобразовать представления U + 1F600 Grinning Face: от кода точки числа 0x1F600 к единичной последовательности UTF-16 код 0xD83D, 0xDE00

что в C# будет:

string face = Char.ConvertFromUtf32(0x1F619); // "" aka "\uD83D\uDE00" 

или в другом направлении:

int codepoint = Char.ConvertToUtf32("\uD83D\uDE00", 0); // 0x1F619 

(здесь названо «UTF-32»; мы говорим о номере целочисленного кода, а не о последовательности из четырех байтов на символ.)

Или есть известный трюк? (например, «символ + ('a' - 'A')", чтобы преобразовать верхний регистр в верхний регистр)

В C++ вещи более раздражают; я не думаю (что я могу думать) о том, что непосредственно преобразует между кодовыми точками и кодовыми единицами UTF-16. Вы можете использовать различные функции/библиотеки кодирования для преобразования между последовательностями байтов с кодировкой UTF-32 и кодовыми единицами UTF-16, но это может привести к большему риску, чем просто написать conversion logic. например, в наиболее общем виде для одного символа:

std::wstring fromCodePoint(int codePoint) { 
    if (codePoint < 0x10000) { 
     return std::wstring(1, (wchar_t)codePoint); 
    } 
    wchar_t codeUnits[2] = { 
     0xD800 + ((codePoint - 0x10000) >> 10), 
     0xDC00 + ((codePoint - 0x10000) & 0x3FF) 
    }; 
    return std::wstring(codeUnits, 2); 
} 

Это предполагает, что wchar_t типа основан на UTF-16 единиц коды, так же, как C# 's string типа. В Windows это, вероятно, так. В другом месте, вероятно, нет, но на платформах, где wchar_t основан на кодовых точках, вы можете просто вытащить каждую кодовую точку из строки в качестве символа без дальнейшей обработки.

(оптимизация и обработка ошибок в качестве упражнения для читателя.)

0

Я использую RAD Studio компилятор, и к счастью, она обеспечивает реализацию функций ConvertFromUtf32 и ConvertToUtf32 упомянутых bobince. Я проверил их, и они сделали именно то, что мне было нужно.

Для тех, кто не использует продукты Embarcadero, реализация fromCodePoint(), предоставляемая bobince, также хорошо работает. Для получения дополнительной информации, здесь также функция ConvertFromUtf32(), реализованные в RAD Studio, и переведен на C++

std::wstring ConvertFromUtf32(unsigned c) 
{ 
    const unsigned unicodeLastChar = 1114111; 
    const wchar_t minHighSurrogate = 0xD800; 
    const wchar_t minLowSurrogate = 0xDC00; 
    const wchar_t maxLowSurrogate = 0xDFFF; 

    // is UTF32 value out of bounds? 
    if (c > unicodeLastChar || (c >= minHighSurrogate && c <= maxLowSurrogate)) 
     throw "Argument out of range - invalid UTF32 value"; 

    std::wstring result; 

    // is UTF32 value a 16 bit value that can fit inside a wchar_t? 
    if (c < 0x10000) 
     result = wchar_t(c); 
    else 
    { 
     // do divide in 2 chars 
     c -= 0x10000; 

     // convert code point value to UTF16 string 
     result = wchar_t((c/0x400) + minHighSurrogate); 
     result += wchar_t((c % 0x400) + minLowSurrogate); 
    } 

    return result; 
} 

Благодаря bobince за его ответ, который указал мне в правильном направлении, и помог мне решить эту проблему.

С уважением