mixi engineer blog

*** 引っ越しました。最新の情報はこちら → https://medium.com/mixi-developers *** ミクシィ・グループで、実際に開発に携わっているエンジニア達が執筆している公式ブログです。様々なサービスの開発や運用を行っていく際に得た技術情報から採用情報まで、有益な情報を幅広く取り扱っています。

絵文字だョ! 符号化文字集合(後編)

同僚の女性からクッキーをすすめられても、「サードパーティークッキーは拒否します」とキッパリお断り申し上げたiPhoneアプリ開発担当の七尾です。というか、どう考えてもホワイトデーの(ry

さて先週に引き続き、iOS開発でUnicode絵文字を扱う際の注意点について書いていこうと思います。

Combining Character/結合文字

サロゲートペアの他にも同様に気をつけなければいけないのが、結合文字です。
アルファベットに対しての修飾文字を付けたり、数字を四角で囲ったりした文字があります。
そういった文字は結合文字と呼ばれ、iPhoneで入力できる文字でいうと、

1を四角で囲った文字 = 0x31 0x20E3
2を四角で囲った文字 = 0x32 0x20E3

というようになります。
結合文字の文字数を取りたい場合は、特定の修飾文字を読み飛ばせば良いだけなので、
以下のようにさらっと対応することが可能です。

unichar c = [emoji characterAtIndex:i];
if (c == 0x20E3) {
    // 囲い文字 なので、文字数カウントしない
}
else {
    ++count;
}

Regional Indicator/国旗絵文字

絵文字の文字数を取る上で最も面倒なのが、国旗絵文字です。なぜなら国旗絵文字はサロゲートペアによる合字だからです。

Unicodeへ絵文字追加の提案がされた時にベースとなったのは携帯電話3キャリアの絵文字ですが、その中には10ヶ国の国旗の絵文字が含まれています。
しかしUnicodeは国際規格なので、その10ヶ国分だけを収録するわけにはいかない。。。というのは容易に想像が付きます。
そこで考案されたのが、国旗用にアルファベットの範囲を決め、日本ならJとP、アメリカならUとS、と言ったように、アルファベット2文字の組み合わせで国旗を表すようにしようという考えです。

上記の案は実際にUnicodeに取り入れられ、その国旗用のアルファベット文字はRegional Indicatorと呼ばれています
図の4つの国旗はiPhoneで入力できる絵文字の一部ですが、確かに2つの文字を合わせたものになっています。
具体的にはU+1F1E6(UTF16: 0xD83C 0xDDE6)からU+1F1FF(UTF16: 0xD83C 0xDDFF)までです。
全てサロゲートペアの文字ですね。本当にありがとうございました。

ここまで調べた段階ですでにグッタリしていまい、何もやる気は起きないわけですが、
国旗絵文字だけをカウントする処理をどうにか実装しようとすると以下のような感じでしょうか。

unichar c = [emoji characterAtIndex:i];
if (0xDDE6 <= c && c <= 0xDDFF) {
    // 国旗絵文字のLow Surrogatesなので、工夫する :)
    if (YES==isRegionalIndicator) {
        // 2文字目のRegional IndicatorのLow Surrogatesは
        // 1つ手前のHigh Surrogates をカウントしてしまっているので、
        // その分デクリメントする
        isRegionalIndicator = NO;
        --count;
    }
    else {
        // 1文字目のRegional Indicatorはカウントせず
        // 次のRegional IndicatorのLow Surrogates為に
        // フラグを立てておく
        isRegionalIndicator = YES;
    }
}
else {
    ++count;
}

しかし実際には絵文字全般を1文字としてカウントしたい場合がほとんどなので、 他のサロゲートペアのカウントも対応するとなると、国旗判定フラグを利用するなりして工夫する必要がありそうです。
以上を踏まえたNSStringでのきちんとした実装については後日絵文字周りの処理をまとめてgithubに上げたいと思います。今日はこれで勘弁してください。