Java的String.getBytes(“ISO-8859-1”)是否返回字符串中每个2字节字符的第一个字节?

时间:2011-08-05 20:20:15

标签: java android unicode

我认为UCS-2与ISO-8859-1相同

    rawData = new byte[data.length()];
    for(int i=0; i<data.length(); i++) {
        rawData[i] = (byte)(data.charAt(i) & 0xff);
    }

这似乎是错误的。为什么上述代码不等同于data.getBytes("ISO8859_1")?我在Android上。

事实上,事实证明我的一些角色是0xf700 & (byte)。出于某种原因,当您使用XMLHttpRequestCharset: x-user-defined获取二进制文件时会发生这种情况。转换为latin1时,这些字符会变为?(问号)。

2 个答案:

答案 0 :(得分:3)

每个Android documentation

  

未指定此字符串无法在指定的字符集中表示的行为。

实际上,此调用最终会作为采用显式Charset的变体,它会将某些替换序列替换为不可翻译的字符。在Sun JDK中,这是一个单字节值64('?')。

但是,在您对早期答案的评论中,您保证字符串中没有大于'0xFF'的字符值,那么您做错了。 ISO-8859-1是UCS-2 / UTF-16的适当子集。

答案 1 :(得分:2)

原因已经由parsifal的回答解释了。为了完整性,这里的代码相当于data.getBytes("ISO-8859-1")(假设字符串是纯UCS-2字符串,没有代理项对):

byte[] rawdata = new byte[data.length()];
for(int i = 0; i < data.length; i++) {
    char c = data.charAt(i);
    if (c > 255) {
        rawData[i] = (byte)'?';
    }
    else {
        rawData[i] = (byte)c;
    }
}

对于代理人(例如真正的UTF-16),它会变得更复杂:

byte[] rawData = new byte[data.length()];
int j = 0;
for(int i = 0; i < data.length; i++, j++) {
    int c = data.codePointAt(i);
    if(c < 0x100) {
        rawData[j] = (byte)c;
    }
    else {
        rawData[j] = (byte)'?';
        if(c >= 0x10000) {
           // surrogate pair
           i++;
        }
    }
}
if(j < rawData.length) {
   rawData = Arrays.copyOf(rawData, j);
}

或者,只使用charAt()

byte[] rawData = new byte[data.length()];
int j = 0;
for(int i = 0; i < data.length; i++, j++) {
    char c = data.charAt(i);
    if(c < 0x100) {
        rawData[j] = (byte)c;
    }
    else {
        rawData[j] = (byte)'?';
        if(Character.isHighSurrogate(c) && Character.isLowSurrogate(data.charAt(i+1))) {
           // surrogate pair
           i++;
        }
    }
}
if(j < rawData.length) {
   rawData = Arrays.copyOf(rawData, j);
}