어떤 라이브러리를 사용해야합니까?
이 글을 쓰는 시점에서 다음과 같은 세 가지 라이브러리가 있습니다.
Apache Any23 은 ICU4j 3.4를 사용하기 때문에 포함하지 않습니다 .
어느 것이 올바른 문자 세트를 감지했는지 (또는 가능한 한 가깝게) 말하는지?
위의 각 라이브러리에서 감지 한 문자 세트를 인증하는 것은 불가능합니다. 그러나 차례로 요청하고 반환 된 응답의 점수를 매길 수 있습니다.
반환 된 응답의 점수를 매기는 방법?
각 응답에는 한 지점이 할당 될 수 있습니다. 응답이 많을수록 탐지 된 문자 집합의 신뢰도가 높아집니다. 이것은 간단한 채점 방법입니다. 다른 사람들을 정교하게 만들 수 있습니다.
샘플 코드가 있습니까?
다음은 이전 행에서 설명한 전략을 구현하는 전체 스 니펫입니다.
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() + " }";
}
개선 :
이 guessEncoding
방법은 입력 스트림을 완전히 읽습니다. 큰 입력 스트림의 경우 이것이 문제가 될 수 있습니다. 이 모든 라이브러리는 전체 입력 스트림을 읽습니다. 이는 문자셋을 탐지하는 데 많은 시간이 소요됨을 의미합니다.
초기 데이터로드를 몇 바이트로 제한하고 그 몇 바이트에서만 문자 세트 감지를 수행 할 수 있습니다.