2010-01-27 4 views
4

편집 :이 질문은 다소 비관적입니다. 응답 한 사람들에게 감사드립니다. 좀 더 구체적 인 후속 질문을 게시 할 수 있습니다.Java 1.6 Windows-1252 인코딩이 3 자로 실패합니다.

오늘은 어떤 인코딩 문제를 투자하고 기본 생식 경우 분리하기 위해 단위 테스트를 썼다 :

int badCount = 0; 
for (int i = 1; i < 255; i++) { 
    String str = "Hi " + new String(new char[] { (char) i }); 

    String toLatin1 = new String(str.getBytes("UTF-8"), "latin1"); 
    assertEquals(str, new String(toLatin1.getBytes("latin1"), "UTF-8")); 

    String toWin1252 = new String(str.getBytes("UTF-8"), "Windows-1252"); 
    String fromWin1252 = new String(toWin1252.getBytes("Windows-1252"), "UTF-8"); 

    if (!str.equals(fromWin1252)) { 
     System.out.println("Can't encode: " + i + " - " + str + 
          " - encodes as: " + fromWin1252); 
     badCount++; 
    } 
} 

System.out.println("Bad count: " + badCount); 

출력 :

 
    Can't encode: 129 - Hi ? - encodes as: Hi ?? 
    Can't encode: 141 - Hi ? - encodes as: Hi ?? 
    Can't encode: 143 - Hi ? - encodes as: Hi ?? 
    Can't encode: 144 - Hi ? - encodes as: Hi ?? 
    Can't encode: 157 - Hi ? - encodes as: Hi ?? 
    Can't encode: 193 - Hi Á - encodes as: Hi ?? 
    Can't encode: 205 - Hi Í - encodes as: Hi ?? 
    Can't encode: 207 - Hi Ï - encodes as: Hi ?? 
    Can't encode: 208 - Hi ? - encodes as: Hi ?? 
    Can't encode: 221 - Hi ? - encodes as: Hi ?? 
    Bad count: 10 

JDK 1.6.0_07 맥 OS 10.6에 있습니다. 2

내 관찰 :

Latin1 대칭 모든 254자를 암호화합니다. Windows-1252는 그렇지 않습니다. 세 개의 인쇄 가능한 문자 (193, 205, 207)는 Latin1과 Windows-1252의 동일한 코드이므로 어떤 문제도 기대하지 않습니다.

누구든지이 동작을 설명 할 수 있습니까? 이것은 JDK 버그입니까?

- 그것은 아무 의미 론적 의미를 문자열 사이에 효과적으로 쓸모 변환을 만들기 때문에 제임스

제 생각에는
+0

게시 한 코드가 의미가 없습니다 (문자열에서 UTF-8 인코딩 된 데이터를 가져 와서 그것을 마치 * latin1 *처럼 해석). 그러므로 당신이하려고하는 것을 따라하기가 꽤 어렵습니다. –

+0

Windows-1252로 변환해야하는 UTF-8로 인코딩 된 일부 데이터가 있습니다. 필자의 프로덕션 시스템에서는 이것이 문자 193에서 실패했음을 알게되었으므로이 기본 복제 사례를 작성했으며 놀랍게도이 10 개의 문자가 Windows-1252와 UTF-8을 대칭으로 인코딩하지 않는다는 사실을 발견했습니다. 모든 254자를 UTF-8과 Latin1 사이에서 인코딩 할 수 있습니다. 그러므로 나의 놀람과 혼란. 그게 도움이 되니? –

+0

정확히 ** ** "코드 변환"이란 것을 의미합니까? 동일한 글리프를 나타내는 Windows-1252 인코딩 된 바이트를 원합니까? 그렇다면 UTF-8이 모든 유니 코드 문자를 나타낼 수 있기 때문에 모든 경우에서 이것이 가능하지 않다는 것을 알아야합니다. Windows-1252는 분명히 할 수 없습니다. –

답변

4

은 테스트 프로그램은, 깊이 결함이있다. 모든 바이트 값이 유효한 값이 주어진 인코딩되어 있는지 확인하려면

,이 같은 일이 그것 같이 더 많은 것 수 있습니다 :이 테스트 프로그램 테스트 입력을 사용하는 것이

public static void tryEncoding(final String encoding) throws UnsupportedEncodingException { 
    int badCount = 0; 
    for (int i = 1; i < 255; i++) { 
     byte[] bytes = new byte[] { (byte) i }; 

     String toString = new String(bytes, encoding); 
     byte[] fromString = toString.getBytes(encoding); 

     if (!Arrays.equals(bytes, fromString)) { 
      System.out.println("Can't encode: " + i + " - in: " + Arrays.toString(bytes) + "/ out: " 
        + Arrays.toString(fromString) + " - result: " + toString); 
      badCount++; 
     } 
    } 

    System.out.println("Bad count: " + badCount); 
} 

참고 (usnigned) 바이트는 해당 코드가 255

1 내지 (이 범위에 유니 코드 코드 포인트에 해당)을 char 값을 사용하여 1 내지 255 값들로 프로그램에 의해 처리되는 실제 바이트 어레이를 인쇄 예를 들어 보면 실제로 모든 바이트 값을 검사하지 않고 "나쁜"일치 항목 중 일부는 다른 항목과 중복됩니다. Windows-1252는 바이트 (129), 1441, 143, 144, 157 개 등의 유효 값을 값에 동의하지 않는다는 것을 말해 준다

 
Can't encode: 129 - in: [-127]/ out: [63] - result: � 
Can't encode: 141 - in: [-115]/ out: [63] - result: � 
Can't encode: 143 - in: [-113]/ out: [63] - result: � 
Can't encode: 144 - in: [-112]/ out: [63] - result: � 
Can't encode: 157 - in: [-99]/ out: [63] - result: � 
Bad count: 5 

: 인수와 "Windows-1252" 이것을 실행

이 출력을 생성한다. (참고 : 여기서 부호없는 바이트 값에 대해 말하고 있습니다. 위의 코드는 -127, -115, ...은 Java가 부호없는 바이트 만 알고 있기 때문에 표시합니다.

The Wikipedia article on Windows-1252

이 진술하여이 관찰을 확인하는 것 같다, 마이크로 소프트와 유니 코드 컨소시엄의 웹 사이트에있는 정보에 따르면

을 81, 8D, 8 층, 90, 및 9D가 사용되지 않는 배치

+0

요아킴,이 시험에 감사드립니다. 문자 193, 205 및 207은 위의 출력에 없습니다. 왜 그들은 Windows-1252에서 제대로 인코딩되지 않지만 Latin1에서 인코딩합니까? 이 코드는 두 코드 페이지에서 같은 문자로 매핑됩니다. –

+0

@James : "왜 Windows-1252에서 제대로 인코딩되지 않습니까?"라는 질문은 잘못된 것입니다. U + 00C1 문자 (코드 포인트 193)는 UTF-8에서 0xC3 0x81로 표시됩니다. 이러한 바이트를 Windows-1252로 해석하려고하면 0x81이 Windows-1252에 유효한 값이 아니며 대체 문자로 바뀝니다. –

+0

그건 의미가 있습니다. 고맙습니다. 이 문제가 혼란 스럽기 때문에 새로운 질문을 열어야합니다. 내 사과. –

2

코드가 수행하는 것 (String->byte[]->String, 두 번)은 인데 반대로 코드 변환은이며 사실상 데이터를 잃을 수 있습니다.트랜스 코딩 byte[]->String->byte[] 의미 : 입력 대상 인코딩이 지원하지 않는 문자가 포함 된 경우

public byte[] transcode(byte[] input, String inputEnc, String targetEnc) 
{ 
    return new String(input, inputEnc).getBytes(targetEnc); 
} 

그리고 물론

, 그것은 데이터가 손실됩니다.

+0

내 사례와 어떻게 다른지 잘 모르겠습니다. 인코딩이 실제로 인코딩되는 것을 보여주는 예제를 게시 할 수 있습니까? 내 테스트는 코드가 내 방식과 정확히 일치 함을 나타냅니다. UTF-8로 인코딩 된 바이트 배열이 있고 대상 인코딩으로 "Windows-1252"를 전달하는 경우 제대로 인코딩 된 문자열을 반환하지 않습니다. 넌 횡설수설 할거야. Charset transcode() 구현을 참조하십시오. 그게 우리가 한 일이라고 생각해. –

+0

@James 자바 문자열이 무엇인지에 대해 오해하고있는 것 같습니다. 그들은 * 디코딩 * 문자 (내부적으로 UTF-16을 사용하지만, 여기서는 관련 없음)입니다. 문자열을 디코딩 할 수 없습니다. 바이트 배열은 String으로 디코드되고 String은 바이트 배열로 인코딩됩니다. 바이트 배열은 추상 문자열의 인코딩에 종속적 인 구체적 표현이므로 트랜스 코딩은 바이트 배열로 시작하고 끝납니다. –

+0

감사합니다. 문자열이 부적절하게 업스트림 (일부 DAO 코드에서 MySQL에 부적절하게 저장된 데이터로 인해)으로 작성된 응용 프로그램을 유지 관리하고 있습니다. 원시 바이트는 UTF-8 이었지만 문자열은 Windows-1252로 작성되었습니다. 내 목표는 Java 문자열을 가져 오는 것이 었습니다.이 문자열은 내가 지금 가지고있는 모든 것이며, 어떻게 든 그것을 횡설수설하지 않으므로 너무 횡설수설하지 않습니다. 나는 근본 원인 등을 푸는 것이 아니라, 때로는 유지 보수 공학에 대한 우리의 곤경을 해결한다는 것을 알고 있습니다. Windows-1252에 0x81이 정의되어 있지 않은 Jochaim의 대답은 왜 그 캐릭터를 복구 할 수 없는지 설명합니다. –