2016-09-20 3 views
0

J'écris actuellement ma propre fonction DrawTextEx() qui prend en charge les émoticônes. Grâce à cette fonction, un rappel est appelé chaque fois qu'une émoticône est trouvée dans le texte, ce qui permet à l'appelant de remplacer le segment de texte contenant l'émoticône par une image. Par exemple, les caractères Unicode 0x3DD8 0x00DE trouvés dans un texte seront remplacés par une image de visage souriant pendant que le texte est dessiné. En fait, cette fonction fonctionne bien.Conversion d'un code d'émoticône "entité HTML" en UTF16 (en C++)

Maintenant, je veux implémenter une bibliothèque d'images du côté de l'appelant. Je reçois un segment de texte comme 0x3DD8 0x00DE dans ma fonction de rappel, et mon idée est d'utiliser ce code comme clé dans une carte contenant toutes les combinaisons Unicode, toutes liées à une structure contenant l'image à dessiner. J'ai trouvé un bon paquet sur le site Web http://emojione.com/developers/. Tous les paquets disponibles sur ce site contiennent plusieurs noms de fichiers, c'est-à-dire un code hexadécimal. Je peux donc parcourir les fichiers contenus dans le paquet et créer ma carte de manière automatique.

Cependant, j'ai trouvé que ces codes font partie d'un autre standard, et sont en fait un ensemble d'éléments nommés "entité HTML", apparemment utilisé dans le développement web, comme on peut le voir sur le site web http://graphemica.com/%F0%9F%98%80. Donc, pour pouvoir utiliser ces fichiers, j'ai besoin d'une solution pour convertir les valeurs d'entité HTML contenues dans leurs noms en un code UTF16. Par exemple, dans le cas du visage souriant mentionné ci-dessus, j'ai besoin de convertir le code d'entité HTML 0x1f600 en 0x3DD8 code 0x00DE UTF16. Une approche de force brute peut consister à écrire une carte qui convertit ces codes, en ajoutant chacun d'eux dans mon code, un par un. Mais comme la norme Unicode contient, dans le scénario le plus optimiste, plus de 1800 combinaisons pour les émoticônes, je veux savoir qu'il existe une solution existante, telle qu'une API ou une fonction connue, que je peux utiliser pour faire le travail. Ou y a-t-il un truc connu pour faire ça? (Comme par exemple "caractère + ('a' - 'A')" pour convertir un omble chevalier en majuscules pour abaisser)

Cordialement

Répondre

1

Par exemple, l'Unicode carbonise 0x3DD8 0x00DE trouvé dans un texte sera remplacé par une image de visage de sourire

le caractère U + 1F600 Grinning visage est représenté par la séquence d'unité de codage UTF-16 0xD83D, 0xDE00.

(Graphemica permutation de l'ordre des octets pour chaque unité de code est super trompeur, ignorer.)

J'ai trouvé que ces codes font partie d'une autre norme, et sont en fait un ensemble d'éléments du nom "Entité HTML", apparemment utilisée dans le développement web

HTML n'a rien à voir avec ça. Ce sont des caractères Unicode simples, juste en dehors du plan multilingue de base, au-dessus de U + FFFF, c'est pourquoi il faut plus d'une unité de code UTF-16 pour les représenter.

Les références de caractères numériques HTML comme 😀 (souvent incorrectement appelées entités) sont un moyen de faire référence aux caractères par numéro de point de code, mais la chaîne d'échappement n'est efficace que dans un document HTML (ou XML), et nous sommes pas dans l'un de ceux-là.

Alors:

J'ai besoin de convertir le code de l'entité 0x1f600 HTML au code 0x3DD8 0x00DE UTF16.

ressemble plus:

J'ai besoin de convertir des représentations de U + 1F600 Grinning Face: à partir du numéro de point de code 0x1F600 à la séquence de l'unité code UTF-16 0xD83D, 0xDE00

qui en C# serait:

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

ou dans l'autre sens:

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

(le nom 'UTF-32' est mal choisi ici; nous parlons d'un numéro de point de code entier, pas d'une séquence de quatre octets par caractère.)

Ou y at-il une astuce connue pour faire cela? (par exemple, "character + ('a' - 'A')" pour convertir un caractère majuscule en un chiffre inférieur)

En C++, les choses sont plus ennuyantes; il n'y a pas (ce que je peux penser) tout ce qui convertit directement entre les points de code et les unités de code UTF-16. Vous pouvez utiliser différentes fonctions/bibliothèques de codage pour convertir des séquences d'octets codées en UTF-32 et des unités de code UTF-16, mais cela peut se traduire par plus de faff que d'écrire vous-même le conversion logic. par exemple, dans la plupart sous forme de base pour un seul caractère:

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); 
} 

Cela suppose le type wchar_t est basé sur des unités de code UTF-16, même que le type de string C# est. Sur Windows, c'est probablement vrai. Ailleurs, ce n'est probablement pas le cas, mais sur les plates-formes où wchar_t est basé sur des points de code, vous pouvez simplement extraire chaque point de code de la chaîne en tant que caractère sans autre traitement.

(Optimisation et gestion des erreurs gauche comme un exercice pour le lecteur.)

0

J'utilise le compilateur RAD Studio, et heureusement, il fournit une implémentation pour les fonctions ConvertFromUtf32 et ConvertToUtf32 mentionnées par bobince. Je les ai testés et ils font exactement ce dont j'avais besoin.

Pour ceux qui n'utilisent pas les produits Embarcadero, l'implémentation fromCodePoint() fournie par bobince fonctionne également bien. Pour plus d'informations, voici également la fonction ConvertFromUtf32() telle que transposée dans RAD Studio, et traduit en 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; 
} 

Merci à bobince pour sa réponse, qui m'a orienté dans la bonne direction et m'a aidé à résoudre ce problème.

Cordialement