Jelly Bean以前とKitKatで扱えるShift-JIS関係のCharsetが変わっていることに気付いたのでメモ。
Charset.availableCharsets()
で使用可能なCharsetの一覧を取得してみると、Jelly Beanでは以下のCharsetを扱える事がわかる。
x-docomo-shift_jis-2007
x-kddi-shift_jis-2007
x-softbank-shift_jis-2007
しかし、KitKatでは上記のCharsetが扱えなくなり、代わりに以下のCharsetが扱えるようになっている。
x-docomo-shift_jis-2012
x-kddi-shift_jis-2012
x-softbank-shift_jis-2012
このようなCharsetがサポートされていること自体あまり知られていないのだが、何が変わったかというと、xxx-2007ではテキスト内にキャリア絵文字が含まれていた場合、Unicodeに変換するとAndroid PUAに変換されるが、
xxx-2012ではUnicode6.0絵文字に変換される。
本当かどうかを太陽の絵文字をSJISからStringに変換するテストコードで確認してみる。
// JB以前で動作する
public void testSjis2007Convert() throws UnsupportedEncodingException {
String docomoSun = new String(toSjisBytes(0xf89f), "x-docomo-shift_jis-2007");
String kddiSun = new String(toSjisBytes(0xf660), "x-kddi-shift_jis-2007");
String softbankSun = new String(toSjisBytes(0xf98b), "x-softbank-shift_jis-2007");
// すべてPUAの☀(U+FE000)になっている
assertEquals(0xFE000, docomoSun.codePointAt(0));
assertEquals(0xFE000, kddiSun.codePointAt(0));
assertEquals(0xFE000, softbankSun.codePointAt(0));
}
// KitKat以降で動作する
public void testSjis2012Convert() throws UnsupportedEncodingException {
String docomoSun = new String(toSjisBytes(0xf89f), "x-docomo-shift_jis-2012");
String kddiSun = new String(toSjisBytes(0xf660), "x-kddi-shift_jis-2012");
String softbankSun = new String(toSjisBytes(0xf98b), "x-softbank-shift_jis-2012");
// すべて☀(U+2600)になっている
assertEquals(0x2600, docomoSun.codePointAt(0));
assertEquals(0x2600, kddiSun.codePointAt(0));
assertEquals(0x2600, softbankSun.codePointAt(0));
}
private byte[] toSjisBytes(int code) {
byte firstByte = (byte)(code >> 8);
byte secondByte = (byte)(code & 0xff);
return new byte[] { firstByte, secondByte };
}
これが問題となるのは標準APIを使って絵文字変換を行うようなOSSを使っている場合で、KitKat以降で正しく変換されなくなり、絵文字が文字化けを起こす場合がある。
KitKat以降では絵文字はUnicode6.0で扱ってくれ、PUAのことは忘れてくれ、ということだと思われる。