Perpustakaan mana yang digunakan?
Pada tulisan ini, mereka adalah tiga perpustakaan yang muncul:
Saya tidak memasukkan Apache Any23 karena menggunakan ICU4j 3.4 di bawah tenda.
Bagaimana cara mengetahui charset yang tepat (atau sedekat mungkin) yang terdeteksi ?
Tidak mungkin mengesahkan charset yang terdeteksi oleh masing-masing pustaka di atas. Namun, dimungkinkan untuk meminta mereka secara bergantian dan menilai respons yang dikembalikan.
Bagaimana cara mencetak respons yang dikembalikan?
Setiap respons dapat diberikan satu poin. Semakin banyak poin yang dimiliki respons, semakin percaya diri charset yang terdeteksi. Ini adalah metode penilaian sederhana. Anda bisa menguraikan orang lain.
Apakah ada kode sampel?
Berikut ini cuplikan lengkap yang mengimplementasikan strategi yang dijelaskan dalam baris sebelumnya.
public static String guessEncoding(InputStream input) throws IOException {
// Load input data
long count = 0;
int n = 0, EOF = -1;
byte[] buffer = new byte[4096];
ByteArrayOutputStream output = new ByteArrayOutputStream();
while ((EOF != (n = input.read(buffer))) && (count <= Integer.MAX_VALUE)) {
output.write(buffer, 0, n);
count += n;
}
if (count > Integer.MAX_VALUE) {
throw new RuntimeException("Inputstream too large.");
}
byte[] data = output.toByteArray();
// Detect encoding
Map<String, int[]> encodingsScores = new HashMap<>();
// * GuessEncoding
updateEncodingsScores(encodingsScores, new CharsetToolkit(data).guessEncoding().displayName());
// * ICU4j
CharsetDetector charsetDetector = new CharsetDetector();
charsetDetector.setText(data);
charsetDetector.enableInputFilter(true);
CharsetMatch cm = charsetDetector.detect();
if (cm != null) {
updateEncodingsScores(encodingsScores, cm.getName());
}
// * juniversalchardset
UniversalDetector universalDetector = new UniversalDetector(null);
universalDetector.handleData(data, 0, data.length);
universalDetector.dataEnd();
String encodingName = universalDetector.getDetectedCharset();
if (encodingName != null) {
updateEncodingsScores(encodingsScores, encodingName);
}
// Find winning encoding
Map.Entry<String, int[]> maxEntry = null;
for (Map.Entry<String, int[]> e : encodingsScores.entrySet()) {
if (maxEntry == null || (e.getValue()[0] > maxEntry.getValue()[0])) {
maxEntry = e;
}
}
String winningEncoding = maxEntry.getKey();
//dumpEncodingsScores(encodingsScores);
return winningEncoding;
}
private static void updateEncodingsScores(Map<String, int[]> encodingsScores, String encoding) {
String encodingName = encoding.toLowerCase();
int[] encodingScore = encodingsScores.get(encodingName);
if (encodingScore == null) {
encodingsScores.put(encodingName, new int[] { 1 });
} else {
encodingScore[0]++;
}
}
private static void dumpEncodingsScores(Map<String, int[]> encodingsScores) {
System.out.println(toString(encodingsScores));
}
private static String toString(Map<String, int[]> encodingsScores) {
String GLUE = ", ";
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, int[]> e : encodingsScores.entrySet()) {
sb.append(e.getKey() + ":" + e.getValue()[0] + GLUE);
}
int len = sb.length();
sb.delete(len - GLUE.length(), len);
return "{ " + sb.toString() + " }";
}
Perbaikan:
TheguessEncoding
Metode membaca inputstream sepenuhnya. Untuk aliran input yang besar ini dapat menjadi perhatian. Semua perpustakaan ini akan membaca seluruh inputstream. Ini akan menyiratkan konsumsi waktu yang besar untuk mendeteksi rangkaian karakter.
Dimungkinkan untuk membatasi pemuatan data awal hingga beberapa byte dan melakukan deteksi charset hanya pada beberapa byte tersebut.