絵文字をShift_JISからUnicodeに変換する SoftBank編
携帯サイトの開発をしているけれど、絵文字の扱いに困っていて・・・という人は多いのではないでしょうか。 今回はShift_JISのエンコーディングで送られて来たSoftBankの絵文字をJAVAのアプリケーションで扱うためにUnicodeのコードポイントに変換する方法を説明します。
SoftBank絵文字の範囲と相関
下の表はSoftBankが公開している絵文字のShift_JISとUnicodeのコードポイント(文字番号)の対応表です。この番号をそれぞれ16ビットと32ビットの整数値で表現すると、Shift_JISのエンコーディングとUTF-32エンコーディングとなります。
Shift_JIS | Unicode | |
---|---|---|
1 | 0xF741-0xF79B | U+E101-U+E15A |
2 | 0xF7A1-0xF7F3 | U+E201-U+E253 |
3 | 0xF941-0xF99B | U+E001-U+E05A |
4 | 0xF9A1-0xF9ED | U+E301-U+E34D |
5 | 0xFB41-0xFB8D | U+E401-U+E44C |
6 | 0xFBA1-0xFBD7 | U+E501-U+E537 |
Shift_JISの場合は、外字領域として定義されている0xF040~0xF9FCとIBM拡張文字で使用されている0xFA40~0xFC4Bという領域に絵文字を割り当てています。 Unicodeの場合は、Private Useエリアとして定義されているU+E000~U+F8FFの範囲を割り当てています。
実際にShift_JISの外字領域とされている0xF040と0xF9FCをJAVAでUnicodeのコードポイントに変換して調べてみたところ、Shift_JISの外字領域がUnicodeのPrivateUseエリアに対応付けられているようで、Shift_JISの外字領域の先頭の番号である0xF040はUnicodeのU+E000となっていました。しかし、ソフトバンクの絵文字対応表を見ると、0xF941とU+E001が対応していることになっています。
そのため、JAVAでSoftBank絵文字を、SoftBankが定義しているUnicodeの符号に変換するためには以下に示す方法で計算する必要があります。
Shift_JISのSoftBank絵文字をUnicodeのコードポイントに変換する方法
実際に男の子の絵文字(Shift_JISで0xF941)をUnicodeのコードポイントに変換する過程を例として、変換方法を説明します。次の節に、JAVAで実装した変換処理のソースコードを掲載してますので、参考にしてください。
取得した絵文字がUnicodeではどこを起点としているのか取得する
Shift_JISと、Unicodeのコードポイントの間には一定の規則があります。
1 | 上位1byteが0xF7かつ後ろが0xA0未満 | U+E100が起点 |
---|---|---|
2 | 上位1byteが0xF7かつ後ろが0xA0以上 | U+E200が起点 |
3 | 上位1byteが0xF9かつ後ろが0xA0未満 | U+E000が起点 |
4 | 上位1byteが0xF9かつ後ろが0xA0以上 | U+E300が起点 |
5 | 上位1byteが0xFBかつ後ろが0xA0未満 | U+E400が起点 |
6 | 上位1byteが0xFBかつ後ろが0xA0以上 | U+E500が起点 |
男の子の絵文字はShift_JISで0xF941なので、ルールの3番に該当します。Unicodeに変換する際のコードポイントの起点がU+E000であることがわかりました。
起点から何番目に定義されているのか求める
Shift_JISのエンコーディングでは下位1byteが0x41~か0xA1~という二種類があります。それぞれUnicodeに変換した際の起点が異なるため、いくつ引くのかを求めます。また、Shift_JISでは仕組み上、下位1byteに0x7Fが使われることはないので、それを飛ばして考えるため、0x41~の範囲では0x80未満と0x80以上とで分かれています。
1 | 下位の1byteが0x80未満 | 0x40を引く |
---|---|---|
2 | 下位の1byteが0xA0以上 | 0xA0を引く |
3 | 下位の1byteが0x80以上0xA0未満 | 0x41を引く |
男の子の絵文字の下位1byteは0x41なので、ルール2の表の1番に該当します。0x41-0x40=0x01なので、起点から1番目の文字であることがわかりました。
Unicodeでのコードポイントを求める
「1」で求めたUnicodeの起点に「2」で求めた数字を足せば、Unicodeでのコードポイントを求めることが出来ます。
男の子の絵文字に関して、「1」の結果はU+E000、「2」の結果は0x01でした。U+E000+0x01=U+E001 ということで男の子の絵文字はUnicodeではU+E001であることがわかりました。
Shift_JISのSoftBank絵文字を変換するJAVAのソースコード
Shift_JISのエンコードで渡されたSoftBank絵文字をUnicodeのコードポイントに変換するJAVAのソースコードを以下に記載します。JAVAでは、エンコーディングとしてShift_JISを指定すると、外字領域を扱うことが出来ないため、ほぼ一致していて、かつ外字領域を扱うことが出来るWindows-31Jを指定しています。
private static String toUnicodeSoftBankGlyph(String glyphStr) throws Exception { // Unicodeのままだと正確に変換が行えないため、Windows-31Jのバイト列に byte[] byteArray = glyphStr.getBytes("Windows-31J"); int firstByte = byteArray[0] & 0xFF; int secondByte = byteArray[1] & 0xFF; int base; // 変換ルール1に基づき、起点を取得 if (firstByte == 0xF7) { if (secondByte < 0xA0) { base = 0xE100; } else { base = 0xE200; } } else if (firstByte == 0xF9) { if (secondByte < 0xA0) { base = 0xE000;/*男の子の絵文字変換ルール1*/ } else { base = 0xE300; } } else if (firstByte == 0xFB) { if (secondByte < 0xA0) { base = 0xE400; } else { base = 0xE500; } } else { // 絵文字ではない return null; } // 変換ルール2に基づき、何番目か取得し、ルール1の結果に加算 int uniNum; if (secondByte < 0x80) { uniNum = base + (secondByte - 0x40);/*男の子の絵文字変換ルール2*/ } else if (secondByte > 0xA0) { uniNum = base + (secondByte - 0xA0); } else { uniNum = base + (secondByte - 0x41); } String uniHex = Integer.toHexString(uniNum); return uniHex; }
上記で説明した変換ルールはGET、もしくはPOSTで送信したような場合に使うことが出来ます。しかし、メールに含まれている場合はまた別のルールがあったりとややこしいことこの上ないです!Google Japan Blog11月27日の記事によると、Googleが日本の絵文字をUnicodeに登録しようと動いているようですが、入ったら入ったでまた大変なんじゃないかなー、と思わずにはいられません。