5

BOM이없는 파일의 인코딩을 식별하려고 할 때 특히 파일이 비 ASCII 문자로 시작될 때 문제가 발생합니다.BOM을 사용하지 않고 비 ASCII 문자로 시작하는 파일에 대해 다른 인코딩을 어떻게 식별 할 수 있습니까?

내가 파일을 인코딩을 식별하는 방법에 대한 두 가지 주제를 다음과 발견, 현재

, 나는 파일을 다른 인코딩을 식별하는 클래스를 생성 (예 : UTF-8, UTF-16, UTF-32, UTF-16 없음 BOM 등)

위의 코드는 모든 경우 BOM없이 파일을 ASCII 문자가 아닌 문자로 시작하는 경우를 제외하고는 제대로 작동 할 수

public class UnicodeReader extends Reader { 
private static final int BOM_SIZE = 4; 
private final InputStreamReader reader; 

/** 
* Construct UnicodeReader 
* @param in Input stream. 
* @param defaultEncoding Default encoding to be used if BOM is not found, 
* or <code>null</code> to use system default encoding. 
* @throws IOException If an I/O error occurs. 
*/ 
public UnicodeReader(InputStream in, String defaultEncoding) throws IOException { 
    byte bom[] = new byte[BOM_SIZE]; 
    String encoding; 
    int unread; 
    PushbackInputStream pushbackStream = new PushbackInputStream(in, BOM_SIZE); 
    int n = pushbackStream.read(bom, 0, bom.length); 

    // Read ahead four bytes and check for BOM marks. 
    if ((bom[0] == (byte) 0xEF) && (bom[1] == (byte) 0xBB) && (bom[2] == (byte) 0xBF)) { 
     encoding = "UTF-8"; 
     unread = n - 3; 
    } else if ((bom[0] == (byte) 0xFE) && (bom[1] == (byte) 0xFF)) { 
     encoding = "UTF-16BE"; 
     unread = n - 2; 
    } else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE)) { 
     encoding = "UTF-16LE"; 
     unread = n - 2; 
    } else if ((bom[0] == (byte) 0x00) && (bom[1] == (byte) 0x00) && (bom[2] == (byte) 0xFE) && (bom[3] == (byte) 0xFF)) { 
     encoding = "UTF-32BE"; 
     unread = n - 4; 
    } else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE) && (bom[2] == (byte) 0x00) && (bom[3] == (byte) 0x00)) { 
     encoding = "UTF-32LE"; 
     unread = n - 4; 
    } else { 
     // No BOM detected but still could be UTF-16 
     int found = 0; 
     for (int i = 0; i < 4; i++) { 
      if (bom[i] == (byte) 0x00) 
       found++; 
     } 

     if(found >= 2) { 
      if(bom[0] == (byte) 0x00){ 
       encoding = "UTF-16BE"; 
      } 
      else { 
       encoding = "UTF-16LE"; 
      } 
      unread = n; 
     } 
     else { 
      encoding = defaultEncoding; 
      unread = n; 
     } 
    } 

    // Unread bytes if necessary and skip BOM marks. 
    if (unread > 0) { 
     pushbackStream.unread(bom, (n - unread), unread); 
    } else if (unread < -1) { 
     pushbackStream.unread(bom, 0, 0); 
    } 

    // Use given encoding. 
    if (encoding == null) { 
     reader = new InputStreamReader(pushbackStream); 
    } else { 
     reader = new InputStreamReader(pushbackStream, encoding); 
    } 
} 

public String getEncoding() { 
    return reader.getEncoding(); 
} 

public int read(char[] cbuf, int off, int len) throws IOException { 
    return reader.read(cbuf, off, len); 
} 

public void close() throws IOException { 
    reader.close(); 
} 

}. 이 상황에서 BOM이없는 파일이 여전히 UTF-16인지 확인하는 논리는 올바르게 작동하지 않으므로 인코딩은 기본적으로 UTF-8로 설정됩니다.

BOM이없는 파일의 인코딩을 검사하고 비 ASCII 문자로 시작하는 방법이있는 경우, 특히 UTF-16 NO BOM 파일의 경우?

감사합니다. 어떤 아이디어라도 감사 할 것입니다.

+1

경험적 방법 ... 많은 경우에 프로그램의 * 많은 * (Un * x * file * 명령이 놀라운 예입니다)에 의해 수행됩니다. 나는 "수동으로"(잘 작동하는 내 자신의 휠을 발명)했지만 요즘에는 단순히 "Stephen C"의 대답을 받아 들일 것입니다. 기존 코드를 이미 다시 사용하십시오. – SyntaxT3rr0r

+0

@ SyntaxT3rr0r : 그래,이 문제를 해결하는 좋은 방법입니다. 타사 라이브러리를 제품에 도입하는 데 한계가 있기 때문에 필자가 제공 한 코드를 개선하여 자체 휠을 사용하는 것이 좋습니다. – eagles

답변

1

일반적으로 인코딩이 제공되지 않는 경우이를 확실히 알 수있는 방법이 없습니다.

텍스트 (높은 비트 세트, 설정, 설정, 설정되지 않음, 설정, 설정, 설정, 설정되지 않음)의 특정 패턴으로 UTF-8을 추측 할 수 있지만 여전히 추측입니다.

UTF-16은 어려운 문자입니다. 당신은 성공적으로 같은 스트림에서 BE와 LE를 파싱 할 수 있습니다; 두 가지 방법으로 어떤 문자 (잠재적으로 의미없는 텍스트)를 생성합니다.

일부 코드는 통계 분석을 사용하여 기호 빈도별로 인코딩을 추측하지만 텍스트 (즉 "몽골어 텍스트") 및 빈도 테이블 (텍스트와 일치하지 않을 수도 있음)에 대한 가정이 필요합니다.). 하루가 끝나면 이것은 추측에 불과하며 100 %의 경우에는 도움이되지 않습니다.

+0

Google 제품은 여러 언어를 지원하므로 원본 파일은 확실하지 않습니다. – eagles

1

최선의 방법은 직접 시도하지 않는 것입니다. 대신 기존 라이브러리를 사용하여이 작업을 수행하십시오. Java : How to determine the correct charset encoding of a stream을 참조하십시오. 예를 들어 :

수행 할 수있는 최선이 가장 가능성이 추측하는 것입니다 주목해야한다 파일 인코딩. 일반적인 경우에는 올바른 인코딩을 알아 냈는지 100 % 확신 할 수 없습니다. 즉 파일을 만들 때 사용 된 인코딩입니다.


나는이 타사 라이브러리가 I가 발생하여 파일을 인코딩을 식별 할 수 없습니다 또한 말할 것은 [...] 그들은 나의 요구 사항을 충족하기 위해 개선 될 수있다.

또는 귀하의 요구 사항을 충족시키기가 매우 어렵다는 것을 알고 있습니다. 예 :

  • 가 제공하는 사람 /이 파일이 올바르게 인코딩 (또는 기본 언어)가 무엇인지 명시 업로드 주장, 인코딩의 특정 세트에 자신을 제한 및/또는
  • 은 시스템 받아 들일 시간의 일정 비율을 잘못 가져오고 누군가가 잘못 명시된/추측 된 인코딩을 수정할 수있는 방법을 제공합니다.

사실을 직면하십시오 : 이것은 이론적으로 해결할 수없는 문제입니다.

+0

이 타사 라이브러리에서도 내가 만난 파일의 인코딩을 식별 할 수 없다고 말할 수 있습니다. 어쨌든, 귀하의 정보를 주셔서 감사합니다, 그들은 내 요구 사항을 충족하기 위해 향상시킬 수 있습니다. – eagles

0

유효한 유니 코드 스트림인지 확신 할 수있는 경우 BOM이 없으면 UTF-8이어야하며 (BOM이 필요하지도 않고 권장되지 않기 때문에) UTF-8이 있어야합니다. 입니다.

일부 랜덤 인코딩 인 경우 확실하게 알 수있는 방법이 없습니다. 당신이 희망 할 수있는 최선의 방법은 모든 경우에 정확하게 추측하는 것이 불가능하기 때문에 때로는 잘못되는 경우입니다.

매우 작은 하위 집합으로 가능성을 제한 할 수 있다면 it is possible to improve the odds of your guess being right.

신뢰할 수있는 유일한 방법은 제공 업체가 제공하는 내용을 알려주는 것입니다. 완벽한 신뢰성을 원한다면 그것은 유일한 선택입니다. 신뢰성이 필요 없다면 추측 할 수 있습니다. 그러나 때로는 잘못 추측합니다.

Windows 사용자가되어야한다는 느낌이 들었습니다. 나머지는 거의 처음부터 BOM을 일으키는 경우가 거의 없었기 때문입니다. 필자는 Mac, Linux, Solaris 및 BSD 시스템에서 텍스트의 tgagabyte를 정기적으로 처리하고 UTF-8의 99 % 이상을 처리하며 두 번만 BOM이 포함 된 텍스트를 발견했습니다. 나는 Windows 사람들이 항상 그것에 매달렸다 고 들었다. 사실이라면 선택을 더 쉽게하거나하지 않을 수 있습니다.

+0

네, 맞습니다. 내가 처리 할 파일은 XML 형식이기 때문에 xml 파일에서 XML 처리 소개를 읽어 들여 InputStream 객체에 전달되는 인코딩 정보를 얻으려고 시도합니다. BOM이없는 XML 파일에서 인코딩을 가져올 수없는 경우 해당 인코딩으로 기본 인코딩 (예 : UTF-8)을 사용하십시오. – eagles

+0

@Eason : 그렇다면 XML *에 인코딩이 있어야하기 때문에 쉽습니다. 행운아! – tchrist

관련 문제