2016-09-20 16 views
0

私は現在、絵文字をサポートする独自のDrawTextEx()関数を作成しています。この関数を使用すると、テキスト内に顔文字が見つかるたびにコールバックが呼び出され、顔文字を含むテキストセグメントをイメージで置き換える機会が与えられます。たとえば、テキスト内にあるUnicode文字0x3DD8 0x00DEは、テキストが描画されている間に笑顔のイメージに置き換えられます。実際にこの関数はうまく動作します。「HTMLエンティティ」の絵文字コードをUTF16で変換する(C++で)

今、私は呼び出し側でイメージライブラリを実装したいと思います。私はコールバック関数で0x3DD8 0x00DEのようなテキストセグメントを受け取り、私の考えは、描画する画像を含む構造体にリンクされたすべてのUnicodeの組み合わせを含むマップでこのコードをキーとして使用することです。私はhttp://emojione.com/developers/ウェブサイトで良いパッケージを見つけました。このサイトで利用可能なすべてのパッケージには、16進コードである複数のファイル名が含まれています。そこで、パッケージに含まれているファイルを繰り返し処理し、自動的にマップを作成することができます。

しかし、これらのコードは別の標準の一部であり、実際にはWeb実装で明らかに使われている「HTMLエンティティ」という項目のセットです。http://graphemica.com/%F0%9F%98%80のWebサイトで見ることができます。したがって、これらのファイルを使用できるようにするには、名前に含まれるHTMLエンティティ値をUTF16コードに変換するソリューションが必要です。例えば、上記の笑顔の場合、私は0x1f600 HTMLエンティティコードを0x3DD8 0x00DE UTF16コードに変換する必要があります。

ブルートフォースのアプローチは、これらのコードをそれぞれコードに1つずつ追加して変換するマップを作成することです。しかし、最も楽観的なシナリオでは、Unicode標準には、絵文字の組み合わせが1800以上ありますので、私はそれには既知のAPIや関数などの既存のソリューションがあることを知りたいと思います。または、それを行う既知のトリックはありますか?例えば

よろしく

答えて

1

- (例えば、 "文字+( 'A' 'A')" のように下げるために、大文字の文字を変換するために)、Unicodeは0x3DD8 0x00DEが交換されるテキストで見つかった文字笑顔画像

によって文字U + 1F600ニヤリ顔は、UTF-16コード単位シーケンス0xD83D、0xDE00で表されます。

は(Graphemica各コードユニットのバイトの順序を入れ替えるスーパー紛らわしいである。それを無視する)

Iは、これらのコードは、別の標準の一部であり、実際に名前付きアイテムの集合であることがわかっウェブ開発で明らかに使われた "HTMLエンティティ"

HTMLはそれとは関係ありません。それらは、U + FFFFより上の、Basic Multilingual Planeの外にある単純なUnicode文字です。そのため、それらを表すために複数のUTF-16コードユニットが必要です。

😀のようなHTMLの数字参照は、コードポイント番号で文字を参照する方法ですが、エスケープ文字列はHTML(またはXML)ドキュメントでのみ有効です。それらの1つではありません。だから、

私は0x3DD8 0x00DE UTF16コードに0x1f600 HTMLエンティティコードを変換する必要があります。

私はU + 1F600ニヤリ顔の表現を変換する必要があります:

より聞こえるコードポイント数0x1F600からUTF-16コード単位シーケンス0xD83Dに、0xDE00

C#でされるであろう:

​​

または他の方向に:

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

(名前「UTF-32」はここではあまり選択されません。我々は、文字コードあたり4バイトのシーケンスではなく整数コードポイント番号について話している。

これを行うには、既知のトリックがありますか? (たとえば、大文字を下に変換する「文字+( '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タイプがあるC#のstring型と同じUTF-16コード単位に基づいていると仮定しています。 Windowsでは、これはおそらく真です。それ以外の場所ではおそらくそうではありませんが、wchar_tがコードポイントに基づいているプラ​​ットフォームでは、文字列から各コードポイントを引き出して、それ以上処理することはできません。

(最適化とエラー処理が読者の練習として残して。)

0

私は、RAD Studioのコンパイラを使用していますし、幸いそれはbobince言及ConvertFromUtf32とConvertToUtf32機能の実装を提供します。私はそれらをテストし、彼らは私が必要とするものを正確に行います。

Embarcadero製品を使用しないものについては、bobinceが提供するfromCodePoint()実装もうまく機能します。 RAD Studioで実装され、正しい方向に私を指摘し、この問題を解決するために私を助けた彼の応答のためにbobinceする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; 
} 

おかげに翻訳などの情報については、こちらをConvertFromUtf32()関数でもあります。

よろしくお願いいたします。

関連する問題