Javaで簡単にかつ正確に文字コード判別する方法

Webページなりファイルなりをいろいろ読み込んで処理するときに文字コードめんどくさいですよね。
大切なものなのですが、大半の人にとって文字コードは大事な関心事ではないので
さくっと簡単に、かつミスのないように実装したいところです。

そう考えるとJava文字コード判定するならjuniversalchardetを使うのが今の最良の選択肢でしょう。
独自で作りこんでもいいんですけど2015年も終わりがちかづいているきょうびお勧めできません

juniversalchardet

MozillaによるUniversalchardetのJava実装です。
universalchardetが何かっていうと文字の出現頻度の統計データを元にバイト列の文字コードを判定する手法とその実装のことで
本家MozillaC++で実装して公開していて各種言語実装があります。*1

これのJava版が簡単に使えるので宗教的な理由でもない限りこれを仕込んでおきましょう。
簡易なクローラーとか、とりあえず何でもテキスト読み込むようなツールを作るときに非常に便利です。

使ってみる

とりあえずmavenにこんな感じで設定をして

<dependency>
	<groupId>com.googlecode.juniversalchardet</groupId>
	<artifactId>juniversalchardet</artifactId>
	<version>1.0.3</version>
</dependency>

余談ですが、googlecode来年の2016年1月25日に完全終了しますね。感慨深い。


適当なソースを書きます。
以下の例ではとあるURLから読み込んだHTMLの文字コードを推測してみます。

    public String getEncodingFromUrl(String url) throws Exception {

        UniversalDetector detector = new UniversalDetector(null);
        String encoding;
        try (InputStream in = new URL(url).openStream();
              ByteArrayOutputStream bao = new ByteArrayOutputStream();) {
            byte[] buff = new byte[8000];
            int bytesRead;
            while ((bytesRead = in.read(buff)) != -1) {
                bao.write(buff, 0, bytesRead);
            }
            byte[] data = bao.toByteArray();
            detector.handleData(data, 0, data.length);
            detector.dataEnd();
            encoding = detector.getDetectedCharset();
            detector.reset();
        }
        return encoding;
    }

こんなので、SJISだろうが、UTF8だろうがEUCだろうが簡単に対応できるようになります。
スクレイピングが捗ります