2014-06-29 209 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