2011-01-20 166 views
6

嘿,我只是剛開始嘗試學習Java,並遇到了一些令人困惑的事情!Java Unicode混淆

我從我正在使用的書中輸入一個示例。它將演示 char數據類型。

的代碼如下:

public class CharDemo 
{ 
public static void main(String [] args) 
{ 
char a = 'A'; 
char b = (char) (a + 1); 
System.out.println(a + b); 
System.out.println("a + b is " + a + b); 
int x = 75; 
char y = (char) x; 
char half = '\u00AB'; 
System.out.println("y is " + y + " and half is " + half); 
} 
} 

是困惑我的是位的聲明,焦炭半= '\ u00AB'。該書指出\ u00AB是符號'1/2'的代碼。如上所述,當我從cmd編譯並運行該程序時,該行上生成的符號實際上是'1/2'。

因此,一切看起來都是應該的。我決定玩弄代碼並嘗試一些不同的unicode。我搜索了多個unicode表,發現它們都不符合上述結果。

在每一個我發現它說,該代碼/ u00AB不是爲「1/2」和實際上這個:

http://www.fileformat.info/info/unic...r/ab/index.htm 那麼什麼字符Java中使用集,我還以爲UNICODE應該就是這樣,Uni,只有一個。我已經搜索了幾個小時,無處可以找到一個指出/ u00AB等於1/2的字符集,但這正是我的java編譯器解釋的。

我必須在這裏丟失一些明顯的東西!謝謝你的幫助!

+3

我推薦這篇文章,以幫助理解你所面臨的問題:絕對最低每一個軟件開發人員絕對,積極必須知道的關於Unicode和字符集] (http://www.joelonsoftware.com/articles/Unicode.html) – 2011-01-20 13:26:04

回答

2

Java的一點很棒,就是它基於unicode。這意味着,您可以使用書寫系統中不是英文字母(例如中文或數學符號)的字符,不僅在數據字符串中,而且在函數和變量名稱中。

這是一個在類名和變量名中使用unicode字符的示例代碼。

class 方 { 
    String 北 = "north"; 
    double π = 3.14159; 
} 

class UnicodeTest { 
    public static void main(String[] arg) { 
     方 x1 = new 方(); 
     System.out.println(x1.北); 
     System.out.println(x1.π); 
    } 
} 

Java是在Unicode標準爲更小的一組字符定義值的時候創建的。那時候,人們感覺到16位將足以編碼所有需要的字符。考慮到這一點,Java被設計爲使用UTF-16。實際上,char數據類型最初用於表示16位Unicode代碼點。

UTF-8字符集由RFC 2279指定;

的UTF-16字符集是由RFC 2781

指定UTF-16字符集使用16位值,並因此對字節順序敏感。在這些編碼中,流的字節順序可以由Unicode字符'\ uFEFF'表示的初始字節順序標記指示。字節順序標記進行如下處理:

When decoding, the UTF-16BE and UTF-16LE charsets ignore byte-order marks; when encoding, they do not write byte-order marks. 

When decoding, the UTF-16 charset interprets a byte-order mark to indicate the byte order of the stream but defaults to big-endian if there is no byte-order mark; when encoding, it uses big-endian byte order and writes a big-endian byte-order mark. 

Also see this

+2

UTF-8和UTF-16 **不是**字符集;它們是兩個不同的可變寬度編碼** **非常相同的字符集:** Unicode。 – tchrist 2011-01-20 13:30:45

4

\u00ab字符不是1/2字符;請參閱Unicode.org網站的definitive code page

你看到的是(我認爲)在默認字符編碼不是UTF-8或Latin-1的平臺上使用System.outPrintStream的後果。也許這是@ axtavt的答案建議的一些Windows字符集? (它也有,爲什麼\u00ab顯示爲1/2的一個合理的解釋......而不是一些「圖示」字。)

(在Unicode和拉丁-1,\00BD是爲1/2字符碼點)。

16

這是一個衆所周知的問題與在Windows平臺上的控制檯編碼不匹配。

Java運行時期望系統控制檯使用的編碼與系統默認編碼相同。但是,Windows使用兩個單獨的編碼:ANSI code page (system default encoding) and OEM code page (console encoding)

所以,當您嘗試Unicode字符U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK寫入控制檯,Java運行時預計,控制檯的編碼是ANSI編碼(即Windows-1252你的情況),在此Unicode字符表示爲0xAB。但是,實際控制檯編碼是OEM編碼(您的情況爲CP437),其中0xAB表示。

因此,將數據打印到Windows控制檯與System.out.println()會產生錯誤的結果。

要獲得正確的結果,您可以使用System.console().writer().println()來代替。

+0

謝謝,這是有道理的,但你提到打印數據到Windows控制檯會產生錯誤的結果。這個例子直接來自Java書,作者知道AB將是一半。這是否只是可憐的寫作,他沒有解釋這一點? – Nick 2011-01-20 13:29:47

+1

@尼克:那麼這是一個可憐的寫作。也許作者很少使用非美國的ASCII字母,因此不熟悉這個問題。 – axtavt 2011-01-20 13:49:02

3

0xAB在老的Codepage 437中是1/2,這是Windows終端默認使用的,no matter what codepage you actually set。因此,實際上,char值代表Java程序的「«」字符,並且如果您在GUI中渲染該字符或在一個合理的操作系統上運行該字符,您將獲得該字符。如果您還想在Windows中看到正確的輸出,請將CMD中的字體設置從「柵格字體」切換(單擊左上角的圖標,屬性,字體選項卡)。例如,與龍力控制檯,我可以這樣做:

C:\Users\Documents>java CharDemo 
131 
a + b is AB 
y is K and half is ½  

C:\Users\Documents>chcp 1252 
Active code page: 1252 

C:\Users\Documents>java CharDemo 
131 
a + b is AB 
y is K and half is « 

C:\Users\Documents>chcp 437 
Active code page: 437