2009-09-29 13 views
4

이번에는이 모든 내용을 무시한 채 현재 Java에서 유니 코드에 대해 자세히 배우고 있습니다. UTF-16 문자열을 8 비트 ASCII로 변환 할 필요가있는 연습이 있습니다. 누군가 자바에서 이것을 어떻게 내게 가르쳐 주시겠습니까? 나는 가능한 모든 유니 코드 값을 ASCII로 표현할 수 없다는 것을 이해합니다. 따라서이 경우 0xFF를 초과하는 코드를 단순히 추가 만하면됩니다. 잘못된 데이터도 자동으로 추가되어야합니다.Java에서 UTF-16에서 ASCII로 변환

감사합니다.

+0

"away away"??? 당신은 "버림받은"것을 의미합니까? 버려 졌니? –

+0

처음부터 명확하지 않은 것에 대해 유감스럽게 생각합니다. 사실, 나 자신이 너무 분명하지 않다. 내가 읽은 책의 연습에서는 "0xFF를 초과하는 코드는 단순히 바이트로 캐스팅되어 어쨌든 추가됩니다 (잘못된 데이터를 자동으로 추가해야 함)." – His

+0

0xFF는 ASCII 문자에 대해 유효한 값이 아닙니다. ASCII는 7 비트이므로 가장 높은 유효한 값은 0x7F입니다. –

답변

5

방법은 :

String input = ... // my UTF-16 string 
StringBuilder sb = new StringBuilder(input.length()); 
for (int i = 0; i < input.length(); i++) { 
    char ch = input.charAt(i); 
    if (ch <= 0xFF) { 
     sb.append(ch); 
    } 
} 

byte[] ascii = sb.toString().getBytes("ISO-8859-1"); // aka LATIN-1 

이것은 아마도 우리가 두 번 문자를 복사하기 때문에 큰 문자열이 변환을 수행하는 가장 효율적인 방법은 아니다. 그러나, 그것은 간단하다는 장점이 있습니다.

실제로 엄밀히 말하자면 8 비트 ASCII와 같은 문자 집합이 없습니다. ASCII는 7 비트 문자 세트입니다. LATIN-1은 "8 비트 ASCII"문자 세트 (그리고 유니 코드의 블록 0은 LATIN-1과 동일합니다)에 가장 가까운 것입니다. 그래서 나는 그것이 당신이 의미하는 것이라고 가정 할 것입니다.

편집 : 질문에 대한 업데이트에 비추어,이 솔루션은 더 간단하다 :

String input = ... // my UTF-16 string 
byte[] ascii = new byte[input.length()]; 
for (int i = 0; i < input.length(); i++) { 
    ascii[i] = (byte) input.charAt(i); 
} 

이 솔루션은보다 효율적입니다. 바이트 수를 예상 할 수 있기 때문에 중간 버퍼로 StringBuilder를 사용하지 않고 바이트 배열을 미리 할당하고 (잘린) 문자를 복사 할 수 있습니다.

그러나이 방법으로 잘못된 데이터를 처리하는 것이 현명하다고 나는 확신하지 못합니다.

EDIT 2 : 여기에 하나 더 애매한 "잡았다"가 있습니다. 유니 코드는 실제로 코드 포인트 (문자)가 "대략 21 비트"값 ... 0x000000에서 0x10FFFF ...로 정의되며 대리모를 사용하여> 0x00FFFF 코드를 나타냅니다. 즉, 유니 코드 코드 포인트> 0x00FFFF는 실제로 UTF-16으로 두 개의 "문자"로 표현됩니다. 내 대답이나 다른 사람들도이 (솔직히 비판적 인) 요점을 고려하지 않습니다. 실제로 Java에서 코드 포인트> 0x00FFFF를 다루는 것은 일반적으로 다소 까다 롭습니다. 이것은 'char'가 16 비트 유형이고 String이 'char'로 정의된다는 사실에서 유래합니다.

편집 3 :

String input = ... // my UTF-16 string 
byte[] ascii = new byte[input.length()]; 
for (int i = 0; i < input.length(); i++) { 
    char ch = input.charAt(i); 
    ascii[i] = (ch <= 0xFF) ? (byte) ch : (byte) '?'; 
} 
+0

위의 "편집 2"에 비추어 볼 때 이것을 해결책으로 표시 할 수는 없습니까? 이것은 해결책이 아니므로 그렇게 표시해서는 안됩니다. – rplankenhorn

+0

@rplankenhorn은 - 문제가 ASCII로 유니 코드를 "강제"에 대해 정말이기 때문에 사실, 변환의 두 버전은 **도 대리의 얼굴에 ** 적절한 솔루션입니다. 첫 번째 버전에서는 코드 단위> ​​FF가 제거됩니다. 두 번째 버전에서, 어떤 code-unit> = FF가 "OPTIONS가 추가되었습니다"... OP가 명시 적으로 요구 한 것입니다. (나는 그것이 현명한 접근이라고 생각하지 않는다.) –

2

Java는 내부적으로 UTF-16 형식의 문자열을 나타냅니다. String 객체가 여러분이 시작하는 객체라면, US-ASCII (코드 포인트 0x00-0x7f를 매핑 할 수 있음) 또는 ISO-8859-1 (코드 포인트 0x00-0xff를 매핑 할 수 있음)을 지정할 수있는 String.getBytes(Charset c)을 사용하여 인코딩 할 수 있습니다. "8 비트 ASCII"가 의미하는 것일 수도 있음).

"잘못된 데이터"추가시 ... ASCII 또는 ISO-8859-1 문자열은 특정 범위를 벗어나는 값을 단순히 나타낼 수 없습니다. 내가 getBytes 단순히 대상 문자 집합에서 나타낼 수없는 문자를 삭제합니다 믿습니다. 이것에 대해

+0

"getBytes는 단순히 대상 문자 집합에서 표현할 수없는 문자를 삭제합니다." Charset의 디폴트의 치환 바이트 배열에 의존합니다 ... Javadoc에 따라. –

+0

Javadoc에서도이 문제가 발생했지만 기본 Charset 객체가 구현되는 방법을 찾을 수 없었습니다. Charset.forName ("US-ASCII")을 호출 할 때 실제로 어떤 일이 발생하는지 알고 있습니까? – Phil

11

당신은 쉽게에 대한 java.nio의 사용할 수 있습니다 : 예기치 않은 문자를 처리하는 어쩌면 더 합리적인 솔루션 ASCII로 변환하지 않는 표준 대체 문자로 교체하는 것입니다 솔루션 :

// first encode the utf-16 string as a ByteBuffer 
ByteBuffer bb = Charset.forName("utf-16").encode(CharBuffer.wrap(utf16str)); 
// then decode those bytes as US-ASCII 
CharBuffer ascii = Charset.forName("US-ASCII").decode(bb);
2

이 연습 때문에 수동으로 구현해야하는 것처럼 들립니다. 인코딩 (예 : UTF-16 또는 ASCII)은 바이트 시퀀스를 논리적 문자 (코드 포인트)와 일치시키는 조회 테이블로 생각할 수 있습니다.

자바

는 특정 코드 포인트가 하나 개 또는 두 char 변수로 표현 될 수 있음을 의미하는 문자열이 UTF-16을 사용한다. 당신이 2 ~ char 서로 게이트 쌍을 처리하는 여부는 당신이 당신의 응용 프로그램 (을 검출하기위한 Character class 참조)을 발생하는 것입니다 생각하는 방법을 가능성에 따라 달라집니다. ASCII은 옥텟 (바이트)의 제 7 비트를 사용하므로 값의 유효 범위는 UTF-16 (그들은 단지 넓은 것)이이 범위에 대해 동일한 값을 사용하여 0 ~ 127이다. 이것은이 코드를 확인할 수 있습니다 :

Charset ascii = Charset.forName("US-ASCII"); 
byte[] buffer = new byte[1]; 
char[] cbuf = new char[1]; 
for (int i = 0; i <= 127; i++) { 
    buffer[0] = (byte) i; 
    cbuf[0] = (char) i; 
    String decoded = new String(buffer, ascii); 
    String utf16String = new String(cbuf); 
    if (!utf16String.equals(decoded)) { 
    throw new IllegalStateException(); 
    } 
    System.out.print(utf16String); 
} 
System.out.println("\nOK"); 

따라서, 당신이 bytechar를 주조하여 ASCII로 UTF-16으로 변환 할 수 있습니다.

당신은 자바 문자 인코딩 here에 대한 자세한 내용을보실 수 있습니다.

관련 문제