2009-06-08 2 views
9

다음 코드 고려해운반 유니 대용 값

byte aBytes[] = { (byte)0xff,0x01,0,0, 
        (byte)0xd9,(byte)0x65, 
        (byte)0x03,(byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07, 
        (byte)0x17,(byte)0x33, (byte)0x74, (byte)0x6f, 
        0, 1, 2, 3, 4, 5, 
        0 }; 
String sCompressedBytes = new String(aBytes, "UTF-16"); 
for (int i=0; i<sCompressedBytes.length; i++) { 
    System.out.println(Integer.toHexString(sCompressedBytes.codePointAt(i))); 
} 

을 가져 다음 잘못된 출력 : 다음 단

ff01, 0, fffd, 506, 717, 3374, 6f00, 102, 304, 500. 

, 입력 데이터의 0xd90x9d 변경되면 다음 올바른 출력이 얻어집니다 :

ff01, 0, 9d65, 304, 506, 717, 3374, 6f00, 102, 304, 500. 

현실 기능은 바이트 0xd9이 상위 대리 유니 코드 표식이라는 사실 때문입니다.

질문 : 자바 유니 코드 문자열에서 서로 게이트 바이트 (0xd800 ~ 0xdfff)를 추출, 식별 및 추출 할 수있는 방법이 있습니까?
감사

답변

4

자바 유니 코드 문자열에서 대리 바이트 (0xdfff에 0xd800)를 공급 식별하고 추출하는 방법이 있나요 ?

아무도 언급하지 않았기 때문에 Character 클래스에는 서로 게이트 쌍 작업 방법이 포함되어 있습니다. 예 : isHighSurrogate(char), codePointAt(CharSequence, int)toChars(int). 나는 이것이 명시된 문제의 요점 밖에 있다는 것을 알고 있습니다.

new String(aBytes, "UTF-16"); 

이것은 입력 데이터를 변환하는 디코딩 작업입니다.나는 선택된 디코딩 작업이 입력이 0xfe 0xff 또는 0xff 0xfe (byte order mark)로 시작해야하기 때문에 이것이 합법적이지 않다는 것을 확신합니다. 또한 UTF-16이 variable width encoding이므로 가능한 모든 바이트 값을 올바르게 디코딩 할 수 없습니다.

당신은 문자열에 임의의 바이트의 대칭 변환을 원하는 경우 모든 바이트 값이 유효한 문자이기 때문에 다시, 당신은 8 비트, 단일 바이트 인코딩 더 낫다 :

Charset iso8859_15 = Charset.forName("ISO-8859-15"); 
byte[] data = new byte[256]; 
for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) { 
    data[i - Byte.MIN_VALUE] = (byte) i; 
} 
String asString = new String(data, iso8859_15); 
byte[] encoded = asString.getBytes(iso8859_15); 
System.out.println(Arrays.equals(data, encoded)); 

참고 : 문자 수는 바이트 수와 같습니다 (데이터 크기를 두 배로 늘림). 결과 문자열이 반드시 인쇄용이 될 필요는 없습니다 (가능한 경우 포함 : bunch of control characters).

저는 with Jon입니다.하지만 임의의 바이트 시퀀스를 Java 문자열에 넣는 것은 거의 항상 나쁜 생각입니다.

10

편집 : 이것은 주석

당신은 문자열에서 임의의 이진 데이터를 인코딩 할 경우에서 문제를 해결, 당신은 하지는 일반 텍스트 인코딩을 사용해야합니다. 인코딩에 유효한 텍스트가 없습니다. 임의의 바이너리 데이터 만 가질 수 있습니다.

Base64 여기로가는 길입니다. Java (base class)는 자바 (public class)에 직접 지원되지 않지만, the one in the Apache Commons Codec library과 같이 사용할 수있는 여러 타사 라이브러리가 있습니다.

예, base64는 데이터 크기를 늘리지 만 정보를 잃지 않고 나중에 디코딩 할 수 있습니다.

편집 : 이것은 내가 문제가 당신이 적절한 대리 를 지정하지 않은 것을 믿습니다 원래의 질문

를 해결합니다. 낮은 대리모를 나타내는 바이트를 지정한 다음 상위 대리인을 지정해야합니다. 그런 다음 적절한 코드 포인트를 추가로 확보 할 수 있어야합니다. 귀하의 경우, 귀하는 낮은 대리인을 부여했습니다.

다음은이 설명하는 코드이다 :

public class Test 
{ 
    public static void main(String[] args) 
     throws Exception // Just for simplicity 
    { 
     byte[] data = 
     { 
      0, 0x41, // A 
      (byte) 0xD8, 1, // High surrogate 
      (byte) 0xDC, 2, // Low surrogate 
      0, 0x42, // B 
     }; 

     String text = new String(data, "UTF-16"); 

     System.out.printf("%x\r\n", text.codePointAt(0)); 
     System.out.printf("%x\r\n", text.codePointAt(1)); 
     // Code point at 2 is part of the surrogate pair 
     System.out.printf("%x\r\n", text.codePointAt(3));  
    } 
} 

출력 :

41 
10402 
42 
+0

나는 당신이 옳다고 생각합니다. 나는 단지 같은 결론에 도달했으나 지식이 많은 사람이 이미 대답했는지 다시 확인했다. –

+0

단순히 "(byte) 0xdc, (byte) 0xef"를 삽입하면 "ff01 694ef dcef ..."어느 쪽이 될 수 있습니다. –

+0

답변 해 주셔서 감사합니다. 하지만 문제는 대리 문자를 포함시키는 문제가 아닙니다. 요구 사항은 임의의 바이트 시퀀스 (압축에서 출력 됨)를 Java 문자열에 제공하고이를 다시 동등한 바이트 시퀀스로 읽는 것입니다. –