juniversalchardetを使用して、
- ファイルの文字コードを推測・デコード・コンソールへの表示を行う
- URLエンコードされた文字列をデコードする
の2つのサンプルプログラムを作成してみます。
juniversalchardetとはMozillaによって提供されているライブラリで、バイト列のパターンの出現頻度をもとに文字コードを推測する機能を提供します。現在日本語ではISO-2022-JP, SHIFT-JIS, EUC-JPに対応しています。
開発環境#
下準備#
以下をmaven dependenciesに追加します
pom.xml
1
2
3
4
5
| <dependency>
<groupId>com.googlecode.juniversalchardet</groupId>
<artifactId>juniversalchardet</artifactId>
<version>1.0.3</version>
</dependency>
|
サンプル1. ファイル読み込み#
Detectorクラス#
今回は汎用性のためにInputStreamを引数としてみます。
引数に渡されたInputStreamインスタンスはオフセットが進んでしまう事に注意が必要です。
UniversalDetectorは入力データが全てシングルバイト文字の場合は文字コード判定結果がnullとなります。今回はそのような場合は環境デフォルト値を返すようにしました。
Detector.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import org.mozilla.universalchardet.UniversalDetector;
public class Detector {
public static Charset getCharsetName(InputStream is) throws IOException {
//4kbのメモリバッファを確保する
byte[] buf = new byte[4096];
UniversalDetector detector = new UniversalDetector(null);
//文字コードの推測結果が得られるまでInputStreamを読み進める
int nread;
while ((nread = is.read(buf)) > 0 && !detector.isDone()) {
detector.handleData(buf, 0, nread);
}
//推測結果を取得する
detector.dataEnd();
final String detectedCharset = detector.getDetectedCharset();
detector.reset();
if (detectedCharset != null) {
return Charset.forName(detectedCharset);
}
//文字コードを取得できなかった場合、環境のデフォルトを使用する
return Charset.forName(System.getProperty("file.encoding"));
}
}
|
Mainクラス#
ファイルの文字コードを判別し、コンソールに出力します。
FileInputStreamはmark/resetをサポートしていないため、文字コード判別とコンソール出力で別のインスタンスを生成します。
Main.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
public class Main {
public static void main(String[] args) throws IOException {
final String path = "./test.txt";
Charset cs;
try (FileInputStream fis = new FileInputStream(path)) {
cs = Detector.getCharsetName(fis);
System.out.println("charset:" + cs);
}
try (BufferedReader br =new BufferedReader(new InputStreamReader(new FileInputStream(path), cs))) {
br.lines().forEach(s -> System.out.println(s));
}
}
}
|
実行例#
1
2
| charset:SHIFT-JIS
あいうえお
|
サンプル2. URLのデコード#
追加でApache commons codecを使用します。
pom.xml
1
2
3
4
5
| <dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.12</version>
</dependency>
|
Detectorクラス#
Detector.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import org.mozilla.universalchardet.UniversalDetector;
public class Detector {
public static Charset getCharsetName(byte[] bytes) {
UniversalDetector detector = new UniversalDetector(null);
//入力文字列が短すぎると推測ができないため、入力を繰り返す
while (!detector.isDone()) {
detector.handleData(bytes, 0, bytes.length);
detector.dataEnd();
}
final String charsetName = detector.getDetectedCharset();
detector.reset();
if (charsetName != null) {
return Charset.forName(charsetName);
}
return Charset.forName(System.getProperty("file.encoding"));
}
}
|
Mainクラス#
Main.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.net.URLCodec;
public class Main {
public static void main(String[] args) throws DecoderException, UnsupportedEncodingException {
final String str= "%82%a0%82%a2%82%a4%82%a6%82%a8";
//URLエンコード文字列をパースし、バイト配列にする
byte[] bytes = new URLCodec()
.decode(str, StandardCharsets.ISO_8859_1.name())
.getBytes(StandardCharsets.ISO_8859_1.name());
Charset cs = Detector.getCharsetName(bytes);
System.out.println("charset:"+cs);
//バイト配列を検出したcharsetを用いて文字列にする
final String s = new String(bytes,cs);
System.out.println(s);
}
}
|
実行例#
1
2
| charset:SHIFT-JIS
あいうえお
|