簡體   English   中英

在Java字符串中處理Unicode代理值

[英]Handling Unicode surrogate values in Java strings

請考慮以下代碼:

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.

然而,如果0xd9在輸入數據被改變為0x9d ,則獲得下面的正確的輸出:

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

我意識到這個功能是因為字節0xd9是一個高代理的Unicode標記。

問題:有沒有辦法在Java Unicode字符串中提供,識別和提取代理字節( 0xd8000xdfff )?
謝謝

編輯:這解決了評論中的問題

如果你想在一個字符串編碼任意的二進制數據,你應該使用一個普通的文本編碼。 您沒有該編碼中的有效文本 - 您只有任意二進制數據。

Base64是去這里的方式。 直接在Java中沒有base64支持(無論如何在公共類中),但是您可以使用各種第三方庫,例如Apache Commons Codec庫中的庫

是的,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

有沒有辦法在Java Unicode字符串中提供,識別和提取代理字節(0xd800到0xdfff)?

僅僅因為沒有人提到它,我將指出Character類包括使用代理對的方法。 例如isHighSurrogate(char)codePointAt(CharSequence,int)toChars(int) 我意識到這是除了所述問題的重點之外。

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

這是將轉換輸入數據的解碼操作。 我很確定它不合法,因為所選的解碼操作要求輸入以0xfe 0xff或0xff 0xfe( 字節順序標記 )開始。 此外,並非每個可能的字節值都可以正確解碼,因為UTF-16是可變寬度編碼

如果您希望將任意字節對稱轉換為String並返回,則最好使用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));

注意:字符數將等於字節數(數據大小加倍); 結果字符串不一定是可打印的(盡管包含一堆控制字符 )。

和Jon在一起 - 將任意字節序列放入Java字符串幾乎總是一個壞主意。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM