2016-09-20 147 views
0

我目前正在編寫我自己的DrawTextEx()函數來支持表情符號。使用此功能,每次在文本中找到表情符號時都會調用回調函數,使調用者有機會用圖像替換包含表情符號的文本句段。例如,在文本中找到的Unicode字符0x3DD8 0x00DE在繪製文本時將被替換爲笑臉圖像。其實這個功能工作正常。轉換UTF16中的「HTML實體」表情符號代碼(在C++中)

現在我想在來電方實現一個圖像庫。在我的回調函數中,我收到了一個像0x3DD8 0x00DE的文本段,我的想法是在包含所有Unicode組合的映射中使用此代碼作爲鍵,每個組合都與包含要繪製的圖像的結構鏈接。我在http://emojione.com/developers/網站上找到了一個很好的包裹。本網站上提供的所有軟件包都包含多個文件名,即十六進制代碼。因此,我可以遍歷包中包含的文件,並以自動方式創建我的地圖。

但是,我發現這些代碼是另一個標準的一部分,實際上是一組名爲「HTML實體」的項目,顯然是用於Web開發的,因爲它可以在http://graphemica.com/%F0%9F%98%80網站上看到。因此,爲了能夠使用這些文件,我需要一個解決方案將其名稱中包含的HTML實體值轉換爲UTF16代碼。例如,在上述笑臉的情況下,我需要將0x1f600 HTML實體代碼轉換爲0x3DD8 0x00DE UTF16代碼。

蠻力的方法可能包括編寫一個地圖轉換這些代碼,通過逐個添加它們在我的代碼中的每一個。但是,在最樂觀的情況下,由於Unicode標準包含超過1800個表情符號的組合,我想知道它有一個現有的解決方案,例如已知的API或函數,可以用來完成這項工作。還是有一個已知的伎倆來做到這一點? (如例如 「字符+( 'A' - 'A')」 來轉換大寫字符來降低)

問候

回答

1

例如,unicode字符0x3DD8 0x00DE在文本中發現將被替換通過笑臉圖像

字符U + 1F600笑臉由UTF-16代碼單元序列0xD83D,0xDE00表示。

(Graphemica交換用於每個碼單元中的字節的順序是超級誤導;忽略。)

我發現,這些代碼是另一個標準的一部分,並且實際上是一個命名的一組項的「HTML實體」,顯然用於網絡開發

HTML與它無關。它們是普通的Unicode字符,只是在U + FFFF之上的基本多語言平面以外的字符,這就是爲什麼它需要多個UTF-16代碼單元來表示它們。

HTML數字字符引用(如😀)(通常不正確地稱爲實體)是通過代碼點編號引用字符的一種方式,但轉義字符串僅在HTML(或XML)文檔中有效,而我們不在其中之一。

所以:

我需要的0x1f600 HTML實體代碼轉換爲0x3DD8 0x00DE UTF16代碼。

聽起來更像:

我需要轉換U + 1F600笑嘻嘻工作面的表示:從所述碼點數目0x1F600爲UTF-16編碼單元序列0xD83D,0xDE00

其中在C#將是:

​​

或在另一個方向:

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#string類型是什麼。在Windows上,這可能是真的。在其他地方,它可能不是,但在wchar_t基於代碼點的平臺上,您可以將每個代碼點作爲字符從字符串中提取出來,而無需進一步處理。

(優化和錯誤處理作爲練習留給讀者。)

0

我使用RAD Studio的編譯器,好在它提供了通過bobince提到ConvertFromUtf32和ConvertToUtf32功能的實現。我測試了他們,他們正是我所需要的。

對於那些不使用Embarcadero產品的人來說,bobince提供的fromCodePoint()實現也很好。有關信息,這裏也爲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他的迴應,這我指出了正確的方向,幫助我解決這個問題的ConvertFromUtf32()函數。

Regards