2014-06-29 167 views
5

我想清理字符,字符序列根据字符集的表示形式,以及如何在Java中将字符集转换为另一个字符集。我有一些困难。字节缓冲区,字符缓冲区,字符串和字符集

例如,

ByteBuffer bybf = ByteBuffer.wrap("Olé".getBytes()); 

我的理解是:

  • 字符串总是存储在Java的UTF-16字节序列(每个字符2个字节,大端)
  • getBytes()结果是这个UTF-16字节序列相同
  • wrap()保持这个序列
  • 因此
  • bybf是字符串的UTF-16大端表示Olé

因此,在该代码:

​​

decode()

  • 解释bybf作为UTF-16串表示
  • 将其“转换”为原始字符串Olé

实际上没有字节应该改变,因为一切都是UTF-16存储的,而UTF-16 Charset应该是一种“中性运算符”。但结果打印为:

?? 

这怎么可能?

其他问题:对于正确地转换,似乎Charset.decode(ByteBuffer bb)要求bb是一个串的UTF-16大端字节序列图像。 这是正确的吗?


编辑:从提供的答案,我做了一些测试,打印ByteBuffer内容,并通过对其进行解码获得的chars。字节[使用= "Olé".getBytes(charsetName)]编码打印在第一行组,其他行是通过解码返回字节[用Charset#decode(ByteBuffer)]与各种Charset获得的字符串。

我还确认在Windows 7计算机上将字符串存储到byte[]的默认编码为windows-1252(除非字符串包含需要UTF-8的字符)。

Default VM encoding: windows-1252 
Sample string: "Olé" 


    getBytes() no CS provided : 79 108 233 <-- default (windows-1252), 1 byte per char 
    Decoded as windows-1252: Olé   <-- using the same CS than getBytes() 
      Decoded as UTF-16: ??   <-- using another CS (doesn't work indeed) 

    getBytes with windows-1252: 79 108 233 <-- same than getBytes() 
    Decoded as windows-1252: Olé 

     getBytes with UTF-8: 79 108 195 169 <-- 'é' in UTF-8 use 2 bytes 
      Decoded as UTF-8: Olé 

     getBytes with UTF-16: 254 255 0 79 0 108 0 233 <-- each char uses 2 bytes with UTF-16 
      Decoded as UTF-16: Olé       (254-255 is an encoding tag) 

回答

7

你大多是正确的。

java中的本地字符表示形式为UTF-16。然而,在将字符转换为字节时,您可以指定您正在使用的字符集,或者系统使用它的默认值,每当我检查时它通常都是UTF-8。如果你正在混合和匹配,这将产生有趣的结果。

例如,我的系统下面

System.out.println(Charset.defaultCharset().name()); 
ByteBuffer bybf = ByteBuffer.wrap("Olé".getBytes()); 
Charset utf16 = Charset.forName("UTF-16"); 
CharBuffer chbf = utf16.decode(bybf); 
System.out.println(chbf); 
bybf = ByteBuffer.wrap("Olé".getBytes(utf16)); 
chbf = utf16.decode(bybf); 
System.out.println(chbf); 

产生

UTF-8
佬쎩
奥莱

因此,这部分是,如果UTF-16是默认的唯一正确字符集
getBytes() result is this same UTF-16 byte sequence.

因此,要么始终指定您使用的最安全的字符集,因为您将始终知道发生了什么,或者始终使用默认值。

+1

大多数Windows系统都不会默认使用utf-8。还不确定“UTF-16 ish”是什么意思。 java使用UTF-16。 – jtahlborn

+0

感谢BevynQ。我目前正在学习Java,你的演示对我来说非常有用。 – mins

+1

@jtahlborn:我的默认CS是windows-1252,直到我将示例字符串更改为“I♥café”。添加心脏使Java切换到UTF-8。很有教育意义。 – mins

7

字符串总是存储在Java的UTF-16字节序列(每个字符2个字节,大端)

是。

getBytes()构造的结果是该相同UTF-16字节序列

号它编码的UTF-16字符到平台默认字符集,无论是。已过时。

包()保持这个序列

wrap()保持一切。因此

bybf是字符串奥莱

号它包装平台的原始字符串的默认编码的UTF-16大尾数表示。

解码()应

  • 解释bybf作为UTF-16字符串表示

否,见上文。

  • 将其“转换”为原始字符串Olé。

除非平台的默认编码是“UTF-16”。

+1

感谢您的详细解答。如果可以选择多个答案,我也会选择它作为正确答案。 [getBytes()](http://docs.oracle.com/javase/8/docs/api/java/lang/String.html#getBytes--)仍然没有被弃用,尽管它是不鼓励的。 – mins

+0

@mins [String.getBytes()](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#getBytes--)的确已被弃用。看到Javadoc。有几个重载不是,但你没有使用它们。 – EJP

+1

@EJP弃用的唯一#getBytes()是['public void getBytes(int srcBegin,int srcEnd,byte [] dst,int dstBegin)'](https://docs.oracle.com/javase/8/ docs/api/java/lang/String.html#getBytes-int-int-byte:A-int-),此方法的所有其他重载版本(包括没有任何参数的版本)都不会被弃用。 – klaar

0

我在使用双字节字符集编码数据时遇到了几乎相同的问题。 上面的答案3包含了您应该密切关注的重大缺陷。

  1. 定义源编码的字符集。
  2. 定义仅用于目标编码的字符集,如果它与本地系统编码不同。

下面的代码工作

public static String convertUTF16ToString(byte[] doc) 
{ 
    final Charset doublebyte = StandardCharsets.UTF_16; 
    // Don't need this because it is my local (system default). 
    //final Charset ansiCharset = StandardCharsets.ISO_8859_1; 

    final CharBuffer encoded = doublebyte.decode(ByteBuffer.wrap(doc)); 
    StringBuffer sb = new StringBuffer(encoded); 
    return sb.toString();   
} 

您最喜爱的编码替换系统默认值。

public static String convertUTF16ToUTF8(byte[] doc) 
{ 
    final Charset doublebyte = StandardCharsets.UTF_16; 
    final Charset utfCharset = StandardCharsets.UTF_8; 
    final Charset ansiCharset = StandardCharsets.ISO_8859_1; 

    final CharBuffer encoded1 = doublebyte.decode(ByteBuffer.wrap(doc)); 
    StringBuffer sb = new StringBuffer(encoded1); 
    final byte[] result = ansiCharset.encode(encoded1).array(); 
    // alternative to utf-8 
    //final byte[] result = utfCharset.encode(encoded1).array(); 

    return new String(result);   
} 
+2

'答案3'没有意义。请提供作者或链接。 – EJP