2009-06-08 47 views
9

Xét đoạn mã sau:Xử lý giá trị thay thế Unicode trong chuỗi Java

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))); 
} 

Gets đầu ra không chính xác như sau:

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

Tuy nhiên, nếu 0xd9 trong các dữ liệu đầu vào được thay đổi để 0x9d, sau đó sản lượng chính xác sau đây thu được:

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

I reali ze rằng chức năng là do thực tế là byte 0xd9 là một điểm đánh dấu Unicode thay thế cao.

Câu hỏi: Có cách nào để nạp, nhận dạng và trích xuất byte thay thế (0xd800 thành 0xdfff) bằng chuỗi Unicode Java không?
Cảm ơn

Trả lời

4

Có cách nào để nuôi, xác định và trích xuất byte thay thế (0xd800 để 0xdfff) trong một chuỗi Java Unicode ?

Chỉ vì không ai đề cập đến nó, tôi sẽ chỉ ra rằng lớp Character bao gồm các phương pháp để làm việc với cặp thay thế. Ví dụ. isHighSurrogate(char), codePointAt(CharSequence, int)toChars(int). Tôi nhận ra rằng điều này ngoài vấn đề được nêu ra.

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

Đây là thao tác giải mã sẽ chuyển đổi dữ liệu đầu vào.Tôi khá chắc chắn nó không phải là hợp pháp bởi vì các hoạt động giải mã được lựa chọn đòi hỏi đầu vào để bắt đầu với 0xfe 0xff hoặc 0xff 0xfe (byte order mark). Ngoài ra, không phải mọi giá trị byte có thể được giải mã một cách chính xác bởi vì UTF-16 là variable width encoding.

Nếu bạn muốn có một sự biến đổi đối xứng của byte tùy ý để String và trở lại, bạn sẽ được tốt hơn off với một 8-bit, mã hóa byte đơn vì mỗi giá trị byte là một ký tự hợp lệ:

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)); 

Lưu ý: số ký tự sẽ bằng số byte (tăng gấp đôi kích thước của dữ liệu); chuỗi kết quả không nhất thiết phải có khả năng in được (có thể có, có thể là bunch of control characters).

Tôi là with Jon, mặc dù - đặt chuỗi byte tùy ý vào chuỗi Java hầu như luôn là ý tưởng tồi.

10

EDIT: Đây giải quyết các câu hỏi từ những nhận xét

Nếu bạn muốn mã hóa dữ liệu nhị phân tùy ý trong một chuỗi, bạn nên không sử dụng một mã hóa văn bản bình thường. Bạn không có văn bản hợp lệ trong mã hóa đó - bạn chỉ có dữ liệu nhị phân tùy ý.

Base64 là cách để đến đây. Không có hỗ trợ base64 trực tiếp trong Java (trong lớp công khai, dù sao) nhưng có nhiều thư viện bên thứ 3 khác nhau mà bạn có thể sử dụng, chẳng hạn như the one in the Apache Commons Codec library.

Có, base64 sẽ tăng kích thước của dữ liệu - nhưng nó sẽ cho phép bạn giải mã sau đó mà không làm mất thông tin.

EDIT: Đây giải quyết các câu hỏi ban đầu

Tôi tin rằng vấn đề là bạn chưa chỉ định một đại diện thích hợp cặp. Bạn nên chỉ định các byte đại diện cho đại diện thay thế thấp và sau đó là đại diện thay thế cao. Sau đó, bạn sẽ có thể thêm điểm mã thích hợp. Trong trường hợp của bạn, bạn đã đưa ra một thay thế thấp của riêng mình.

Dưới đây là code để chứng minh điều này:

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));  
    } 
} 

Output:

41 
10402 
42 
+0

Tôi tin rằng bạn đã đúng. Tôi đã đi đến cùng một kết luận nhưng đã kiểm tra lại để xem liệu có ai hiểu biết hơn đã trả lời hay không. –

+0

Chỉ cần chèn "(byte) 0xdc, (byte) 0xef," yields "ff01 694ef dcef ..." Điều này là đúng. –

+0

Cảm ơn câu trả lời của bạn. Nhưng, vấn đề không phải là về việc nhúng các nhân vật thay thế. Yêu cầu là nạp bất kỳ chuỗi byte tùy ý nào (là đầu ra từ nén) vào một chuỗi Java và đọc nó trở lại như một chuỗi byte tương đương. –

Các vấn đề liên quan