- sun.io.ByteToCharConverter
- sun.io.CharToByteConverter
というクラスがあり、ここから以下のようにConverterを取得することで
CharToByteConverter ascii = CharToByteConverter.getConverter("ASCII"); CharToByteConverter jis0201 = CharToByteConverter.getConverter("JIS0201"); CharToByteConverter jis0208 = CharToByteConverter.getConverter("JIS0208"); CharToByteConverter ms932 = CharToByteConverter.getConverter("MS932");
charを特定の文字集合やエンコーディングで変換可能かどうかを確認できていました。
ascii.canConvert('あ'); // false jis0201.canConvert('あ'); // false jis0208.canConvert('あ'); // true ms932.canConvert('あ'); // true
とはいえ、これ普通にjava.nio.charset.CharsetDecoderでやればよかったですね。困ったらこちらを眺めていることが多かったので、そういえば使ったことありませんでした。
というわけで、試してみましょう。
使用できるエンコーディングは、こちらを参照。
http://docs.oracle.com/javase/jp/7/technotes/guides/intl/encoding.doc.html
http://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html
JIS X 0208とか、普通に指定できたんですね(Charsetの指定は「x-JIS0208」)。知らなかった…。
まずは、CharsetEncoder。
import static org.fest.assertions.api.Assertions.*; import org.junit.Test; // Java 8では、もう使用不能 //import sun.io.ByteToCharConverter; //import sun.io.CharToByteConverter; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.CharBuffer; import java.nio.charset.CoderResult; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import java.nio.charset.StandardCharsets; public class MultiByteConverterTest { // ここに、テストコードを書く!! }
CharsetEncoder。
@Test public void canEncodeTest() { CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder(); CharsetEncoder jisX0201Encoder = Charset.forName("JIS_X0201").newEncoder(); CharsetEncoder jisX0208Encoder = Charset.forName("x-JIS0208").newEncoder(); CharsetEncoder win31jEncoder = Charset.forName("Windows-31J").newEncoder(); char alpha = 'A'; assertThat(asciiEncoder.canEncode(alpha)) .isEqualTo(true); assertThat(jisX0201Encoder.canEncode(alpha)) .isEqualTo(true); assertThat(jisX0208Encoder.canEncode(alpha)) .isEqualTo(false); assertThat(win31jEncoder.canEncode(alpha)) .isEqualTo(true); char hiragana = 'あ'; assertThat(asciiEncoder.canEncode(hiragana)) .isEqualTo(false); assertThat(jisX0201Encoder.canEncode(hiragana)) .isEqualTo(false); assertThat(jisX0208Encoder.canEncode(hiragana)) .isEqualTo(true); assertThat(win31jEncoder.canEncode(hiragana)) .isEqualTo(true); char gaiji = '①'; assertThat(asciiEncoder.canEncode(gaiji)) .isEqualTo(false); assertThat(jisX0201Encoder.canEncode(gaiji)) .isEqualTo(false); assertThat(jisX0208Encoder.canEncode(gaiji)) .isEqualTo(false); assertThat(win31jEncoder.canEncode(gaiji)) .isEqualTo(true); }
CharsetEncoder#canEncodeで確認すればよい、と。
これで、文字が特定のエンコーディングや文字集合に入っているかどうかは、確認することができますね、と。
CharsetDecoderは、ちょっと意に反した結果に?
@Test public void canDecodeTest() { CharsetDecoder asciiDecoder = StandardCharsets.US_ASCII.newDecoder(); CharsetDecoder jisX0201Decoder = Charset.forName("JIS_X0201").newDecoder(); CharsetDecoder jisX0208Decoder = Charset.forName("x-JIS0208").newDecoder(); CharsetDecoder win31jDecoder = Charset.forName("Windows-31J").newDecoder(); byte[] alpha = {(byte)0x41}; // 'A' assertThat(asciiDecoder.decode(ByteBuffer.wrap(alpha), CharBuffer.allocate(1), true).isError()) .isEqualTo(false); assertThat(jisX0201Decoder.decode(ByteBuffer.wrap(alpha), CharBuffer.allocate(1), true).isError()) .isEqualTo(false); assertThat(jisX0208Decoder.decode(ByteBuffer.wrap(alpha), CharBuffer.allocate(1), true).isError()) .isEqualTo(true); assertThat(win31jDecoder.decode(ByteBuffer.wrap(alpha), CharBuffer.allocate(1), true).isError()) .isEqualTo(false); asciiDecoder.reset(); jisX0201Decoder.reset(); jisX0208Decoder.reset(); win31jDecoder.reset(); byte[] hiragana = {(byte)0x82, (byte)0xa0}; // 'あ' assertThat(asciiDecoder.decode(ByteBuffer.wrap(hiragana), CharBuffer.allocate(1), true).isError()) .isEqualTo(true); assertThat(jisX0201Decoder.decode(ByteBuffer.wrap(hiragana), CharBuffer.allocate(1), true).isError()) .isEqualTo(true); assertThat(jisX0208Decoder.decode(ByteBuffer.wrap(hiragana), CharBuffer.allocate(1), true).isError()) .isEqualTo(true); assertThat(win31jDecoder.decode(ByteBuffer.wrap(hiragana), CharBuffer.allocate(1), true).isError()) .isEqualTo(false); asciiDecoder.reset(); jisX0201Decoder.reset(); jisX0208Decoder.reset(); win31jDecoder.reset(); byte[] gaiji = {(byte)0x87, (byte)0x40}; // '①' assertThat(asciiDecoder.decode(ByteBuffer.wrap(gaiji), CharBuffer.allocate(1), true).isError()) .isEqualTo(true); assertThat(jisX0201Decoder.decode(ByteBuffer.wrap(gaiji), CharBuffer.allocate(1), true).isError()) .isEqualTo(true); assertThat(jisX0208Decoder.decode(ByteBuffer.wrap(gaiji), CharBuffer.allocate(1), true).isError()) .isEqualTo(true); assertThat(win31jDecoder.decode(ByteBuffer.wrap(gaiji), CharBuffer.allocate(1), true).isError()) .isEqualTo(false); }
Windows-31Jでないと、マルチバイト文字を理解できませんでした。JIS X シリーズは、エンコーディングというよりは、文字集合だからでしょうか…?
バイト配列を文字に変換できるか確認する時は、普通に「Windows-31J」とか「Shift_JIS」とか「UTF-8」などのエンコーディングを指定すべきなんでしょうね。