2015-07-06 41 views
0

的字符串改變我已經以下代碼:java的UTF-8編碼字節爲奇數個字符

public static void main(String args[]) throws UnsupportedEncodingException { 
    System.setProperty("file.encoding", "gbk"); 

    String name = "こんにちわ"; 
    String copy = new String(name.getBytes("utf-8")); 

    byte[] b1 = name.getBytes("utf-8"); 
    byte[] b2 = copy.getBytes(); 

    System.out.println("b1: " + Arrays.toString(b1)); 
    System.out.println("b2: " + Arrays.toString(b2)); 
} 

控制檯輸出是:

B1:[-29,-127, - 109,-29,-126,-109,-29,-127,-85,-29,-127,-95,-29,-126,-113]
b2:[-29,-127 ,-109,-29,-126,-109,-29,-127,-85,-29,-127,-95,-29,-126,]

注意新字符串中最後一個字節不同。


現在,如果我使用輸入String name = "こんにち";(僅4日本漢字),相反,它更改爲:

B1:[-29,-127,-109,-29,-126 ,-109,-29,-127,-85,-29,-127,-95]
b2:[-29,-127,-109,-29,-126,-109,-29,-127 ,-85,-29,-127,-95]

這次字節完全一樣。


我用java jdk1.6.0_45的窗口。默認字符集是gbk。 我遇到過一些編碼限制嗎?

+2

什麼是您的設置默認字符集? – RealSkeptic

+1

我在兩行上都得到''-113「',在窗口上使用1.6.0_45。 – Keppil

+0

@RealSkeptic默認字符集是gbk – oyss

回答

2

基本上,你的程序的前四行等效於:

String name = "こんにちわ"; 
    byte[] b1 = name.getBytes("utf-8"); 

    String a = new String(name.getBytes("utf-8"), "gbk"); 
    byte[] b2 = a.getBytes("gbk"); 

也就是說,你正在服用的字節數組(b1)這是你的日語字符串的UTF-8表示,以及告知Java「這個字節數組採用GBK編碼,將其轉換爲文本」。

這不起作用,如果你打印你的a字符串,你會發現它不會打印日文文本,而是打印一些中文亂碼 - 最後加上替換字符(「 」)。

在內部,Java字符串以UTF-16編碼。但是當你轉換成字節數組和從字節數組轉換時,你必須指定編碼。編碼彼此不同,並且可以使用相同的字節值或字節值序列來表示完全不同的字符。

而在這種情況下,UTF-8中存在的字節序列在GBK中是不合法的,因此Java將用替換字符替換它們。

如果要從b1創建一個新字符串,並且該字符串仍然是こんにちわ,則需要創建a以告知Java該字節爲UTF-8。

String a = new String(name.getBytes("utf-8"), "utf-8"); 

然後,你a將等於name

然後,如果你只是做a.getBytes(),你會得到代表該字符串的字節在GBK。這將是不同b1,因爲它是在不同的編碼。要獲得相同的數組,您需要使用相同的編碼(a.getBytes("utf-8"))。

  • 儘量不要依賴Java的默認字符集。從字符串獲取字節時以及在將字節轉換爲字符串時,始終指定確切的字符集。
  • 不同的字符集爲同一個字符串生成不同的字節數組。
  • getBytes()String(byte[])沒有字符集參數不給你真實的字節序列,String的基礎。他們使用JVM的默認字符集 - 在你的情況下,GBK。
+0

我試過「new String(name.getBytes(」utf-8「),」utf-8「)」;但它給了我這樣的字節。 「-92」「 - 77」「 - 92」「 - 13」「 - 92」「 - 53」「 - 92」「 - 17」「 - 92」「 - 17」與「こんにわわ」完全不同。的getBytes( 「UTF-8」)。這些字節用於散列,因此它們需要在字節中完全相同以產生相同的散列號。 – oyss

+0

你有沒有看到我說:「要獲得相同的數組,你需要使用相同的編碼('a.getBytes(」utf-8「)')」? – RealSkeptic

+0

錯過了這個部分。現在沒問題。謝謝。 – oyss

1

您正面臨一個常見問題,您正在使用默認平臺編碼,其編碼字節順序不同。 此行

byte[] b1 = name.getBytes("utf-8"); 

字符串轉換您使用UTF-8編碼字節[]。 這條線:

String a = new String(name.getBytes("utf-8")); 

創建從字節數組的字符串,但沒有指定的字符集。這可能是一個問題,因爲jvm「拿起它自己的價值」;請注意,String類還具有以下的構造:

String(byte[] bytes, Charset charset) 

,允許你指定如何使用您作爲第二個參數傳遞的編碼,以創建從字節序列的字符串。

String a = new String(name.getBytes("utf-8"));正在使用默認平臺,從您的評論讀取,是gbk。 所以你真正做的是:

String a = new String(name.getBytes("utf-8"),"gbk"); 

,而不是

String a = new String(name.getBytes("utf-8"),"UTF-8"); 

的「刁鑽」的部分是,一些編碼重疊他們將一些(但不是全部)符號與相同的字節序列;所以它們以某種方式表示一些字符串,但其他字符以不同的方式表示。例如,ISO8859-1代表的字符與ISO8859-15相同,除了歐元和其他一些字符(引入ISO8859-15的單字節包含歐元符號,您可以看到差異here),所以如果字符串不包含€符號,則表示字符串的序列在ISO8859-1和ISO8859-15中相同。

如果你喜歡閱讀與Java編碼也與XML的東西,你可以看看this one

1

不,你不符合編碼的限制,但你的代碼通過可變ab2

使用默認字符集

試試這個:

String a = new String(name.getBytes("UTF-8"),"UTF-8"); 
    byte[] b2 = a.getBytes("UTF-8"); 
相關問題