スポンサーリンク
FreeType2で文字をラスタライズしたいときに、絵文字と日本語でフォントを変えないといけなかったりするので、その自動判別の方法を調べた。絵文字かどうかはUnicodeのBinary Propertyを調べる。アルファベットかひらがなか漢字かなどはScriptで判別可能。
#include <iostream> #include <unicode/ucnv.h> #include <unicode/brkiter.h> #include <unicode/uscript.h> // 要リンク #pragma comment(lib, "icuuc.lib") // icudt67.dll // icuuc67.dll
bool isEmoji(UChar32 c) { // Unicodeの文字にはバイナリプロパティというのがあり、 // そこを調べると文字についての色々な情報がわかる。 // 絵文字かどうかの判別はバイナリプロパティがEmoji系になっているかどうかでわかる int32_t check=0; // cが絵文字ならどれかで非ゼロになるはず check += u_getIntPropertyValue(c, UCHAR_EMOJI); check += u_getIntPropertyValue(c, UCHAR_EMOJI_PRESENTATION); check += u_getIntPropertyValue(c, UCHAR_EMOJI_MODIFIER); check += u_getIntPropertyValue(c, UCHAR_EMOJI_MODIFIER_BASE); check += u_getIntPropertyValue(c, UCHAR_EMOJI_COMPONENT); return (bool)check; }
int main() { std::setlocale(LC_ALL, ""); // 元の文字列の定義 std::u16string u16s = u"👨👧さa感マ"; ///////////////////////////// // ICUの設定 icu::UnicodeString usr(u16s.c_str()); UErrorCode err; icu::BreakIterator* bi = icu::BreakIterator::createCharacterInstance( icu::Locale::getDefault(), err); bi->setText(usr); // イテレータで1書記素ずつループする int32_t current = bi->first(); while (current != icu::BreakIterator::DONE) { // 文字の長さを知る必要があるので、 // 「現在の文字の位置」と「前の文字の位置」が必要 int32_t prev = current; current = bi->next(); if (current == UBRK_DONE) { break; } int32_t count = current - prev;//文字の長さ // UTF16配列としてのprev番目の文字をUTF32で取得 UChar32 c = usr.char32At(prev); // バイナリプロパティで絵文字かどうかチェック if (isEmoji(c) == true) { printf("絵文字\n"); } else{
// スクリプトを取得し文字の種類を特定 UScriptCode script = uscript_getScript(c, &err); switch (script) { case USCRIPT_LATIN: printf("latin\n"); break; case USCRIPT_HIRAGANA: printf("ひらがな\n"); break; case USCRIPT_KATAKANA: printf("カタカナ\n"); break; case USCRIPT_HAN: printf("漢字\n"); break; } } } }