一、JAVA字符集
Java標準字符集:所謂Java標準字符集,就是Java平臺支援的字符集:US-ASCII、ISO-8859-1、UTF-8、UTF-16BE、UTF-16LE、UTF-16。
US-ASCII
US-ASCII,這是一個出現得比較早的字元編碼規範;因為它出現比較早,在通用性方面也考慮得比較少,所以也比較簡單。一個ASCII字元用一個位元組儲存,也就是說它可以用來表示256個不同的字元。由於英文大小寫字母、阿拉伯數字和標點符號等字元是有限的,所以就把前128個字元作為常用字元,而剩下的高位字元作為擴充套件字元。這128個字元通常用來表示音標、特殊字元等。
ISO-8859-1
ISO-8859-1也常被稱為Latin_1(拉丁1)字符集,像MySQL的預設字符集就是ISO-8859-1,其他它與ASCII編碼類似,也是用一個位元組表示一個字元,也只用於表示英文字元、數字、符號及特殊字元。它與ASCII唯一的不同在於它是一個國際標準,而ASCII只是一個美國國家標準。
中文字符集
透過對上面兩種字符集的瞭解,如果想用它們來表示中文字符集,顯然有些不太現實,因為常用的中文字元都有上千個之多,所以我們需要能表示更多字元的字符集實現中文字元編碼。但又為了相容ASCII編碼,中國在ASCII的基礎上制定了自己的字元編碼規範,也就是我們比較熟悉的GB2312,它的全稱是GB2312-80資訊交換用漢字編碼字符集(基礎集)。它能定義了7000多個常用漢字和符號,GB2312的實現是透過使用兩個擴充套件ASCII字元來定義一箇中文字元,根據這一特定,我們就可以判斷相鄰的兩個ASCII字元是否為擴充套件字元,我們就可以確認這兩個字元組成一箇中文字元,但是在擴充套件ASCII字元中,也定義了一些其他字元,所以相鄰兩個ASCII同為擴充套件字元時,並不能肯定的說它是一箇中文字元,處理起來是相當麻煩的。
除了GB2312這個字符集以外,還有幾個中文的字符集:Big5、HKSCS、GBK、GB18030。
——> Big5:臺灣使用的編碼標準,繁體中文字元,字元數也有7000多個。
——> HKSCS:香港使用的編碼標準,繁體中文字元,但跟Big5不同
——> GBK:《漢字內碼擴充套件規範》是GB2312的擴充套件集,不僅增加了大量簡體中文字元和符號,也增加了對繁體中文字元的支援,另外還留有使用者自定義字元空間,總共字元數在22000左右。
——> GB18030:《資訊交換用漢字編碼字符集 基本集的擴充》將會成為中國字元編碼規範新標準,它相容GB2312和GBK。
GB2312、Big5、HKSCS是同一時期的產物,雖然都是透過擴充套件ASCII來實現的,但是它們彼此之間並不相容,GBK作為GB2312的擴充套件產物,它幾乎涵蓋了Big5裡所有的繁體字,並將一些不常見的中文字元也新增進入標準,windows作業系統支援的中文字符集也就是GBK;GB18030是2000年制定的標準,它為了相容GB2312和GBK,保留了雙位元組編碼,同時為了擴充套件,新增了四位元組編碼,擴充套件後的GB18030字符集新增了部分少數民族文字,支援的字元數量比GBK多5000多個。
Unicode
透過對上面知識的學習,你就會覺得Unicode(Universal Multiple-Octet Coded Character Set)的出現是種必然,如果沒有一套統一的字元編碼標準,我們將舉步維艱。Unicode提供了兩套字元編碼標準:
——> UCS-2(Unicode-16):2個位元組字元編碼
——> UCS-4(Unicode-32):4個位元組字元編碼
Unicode編碼能支援的字元數相當多,Unicode-16就能定義65535個字元,其中包含了大量中文字元(一箇中文字元只暫一位)。
其實Unicode是一種理想化的字元標準,它並沒有過多地考慮目前已經存在的字符集標準,它只與ISO-8859-1相容,但它並不與ASCII相容,想從ASCII編碼轉換為Unicode編碼相當困難;另外,Unicode裡很多字元都有‘0’位元組,這將導致C語言會誤認為它為字串結束標誌,這是相當可怕的,如果使用了Unicode編碼,所有用C語言實現的系統將無法正常工作。這也是為何會出現UTF的原因。
UTF編碼
UTF(UCS Transformation Format)實現了Unicode與計算機所使用的編碼之間的對映關係。常用的UTF編碼有:UTF-8、UTF-16、UTF-7等。
——> UTF-8:是三位元組變長字元編碼,它能相容ASCII編碼。
——> UTF-16:是Unicode的標準實現,與Unicode編碼規範相同
——> UTF-16BE:UTF-16編碼big endian,先存放高位元組
——> UTF-16LE:UTF-16編碼little endian,先存放低位元組
其中,big endian和little endian是CPU處理多位元組字元的不同方法,因CPU的不同而有所不同。另外,很多人都認為UTF-8和Unicode是一個概念,其實UTF-8只是Unicode標準的一種編碼實現,是目前使用得比較多的字元編碼格式之一。
PS:一、 各個國家和地區所制定的不同 ANSI 編碼(不同的國家和地區制定了不同的標準,由此產生了 GB2312, BIG5, JIS 等各自的編碼標準。這些使用 2 個位元組來代表一個字元的各種漢字延伸編碼方式,稱為 ANSI 編碼)標準中,都只規定了各自語言所需的“字元”。比如:漢字標準(GB2312)中沒有規定韓國語字元怎樣儲存。這些 ANSI 編碼標準所規定的內容包含兩層含義:
1.使用哪些字元。也就是說哪些漢字,字母和符號會被收入標準中。所包含“字元”的集合就叫做“字符集”。
2.規定每個“字元”分別用一個位元組還是多個位元組儲存,用哪些位元組來儲存,這個規定就叫做“編碼”。
各個國家和地區在制定編碼標準的時候,“字元的集合”和“編碼”一般都是同時制定的。因此,平常我們所說的“字符集”,比如:GB2312, GBK, JIS 等,除了有“字元的集合”這層含義外,同時也包含了“編碼”的含義。
“UNICODE 字符集”包含了各種語言中使用到的所有“字元”。用來給 UNICODE 字符集編碼的標準有很多種,比如:UTF-8, UTF-16, UnicodeLittle, UnicodeBig 等。
二、從計算機對多國語言的支援角度看,大致可以分為三個階段:
階段一 ASCII 計算機剛開始只支援英語,其它語言不能夠在計算機上儲存和顯示。 英文 DOS
階段二 ANSI編碼
(本地化) 為使計算機支援更多語言,通常使用 0x80~0xFF 範圍的 2 個位元組來表示 1 個字元。比如:漢字 '中' 在中文作業系統中,使用 [0xD6,0xD0] 這兩個位元組儲存。
不同的國家和地區制定了不同的標準,由此產生了 GB2312, BIG5, JIS 等各自的編碼標準。這些使用 2 個位元組來代表一個字元的各種漢字延伸編碼方式,稱為 ANSI 編碼。在簡體中文系統下,ANSI 編碼代表 GB2312 編碼,在日文作業系統下,ANSI 編碼代表 JIS 編碼。
不同 ANSI 編碼之間互不相容,當資訊在國際間交流時,無法將屬於兩種語言的文字,儲存在同一段 ANSI 編碼的文字中。 中文 DOS,中文 Windows 95/98,日文 Windows 95/98
階段三 UNICODE
(國際化) 為了使國際間資訊交流更加方便,國際組織制定了 UNICODE 字符集,為各種語言中的每一個字元設定了統一併且唯一的數字編號,以滿足跨語言、跨平臺進行文字轉換、處理的要求。總結:許多Java 程式設計人員永遠不會需要處理字符集編碼轉換問題,而大多數永遠不會建立自定義字符集。但是對於那些需要的人,在 java.nio.charset 和java.charset.spi 中的一系列類為字元處理提供了強大的以及彈性的機制。
Charset(字符集類) 封裝編碼的字符集編碼方案,用來表示與作為位元組序列的字符集不同的字元序列。 CharsetEncoder(字符集編碼類) 編碼引擎,把字元序列轉化成位元組序列。之後位元組序列可以被解碼從而重新構造源字元序列。 CharsetDecoder(字符集解碼器類) 解碼引擎,把編碼的位元組序列轉化為字元序列。 CharsetProvider SPI(字符集供應商 SPI) 透過伺服器供應商機制定位並使 Charset實現可用,從而在執行時環境中使用
字符集:在JVM 啟動時確定預設值,取決於潛在的作業系統環境、區域設定、和/或JVM配置。如果您需要一個指定的字符集,最安全的辦法是明確的命名它。不要假設預設部署與您的開發環境相同。字符集名稱不區分大小寫,也就是,當比較字符集名稱時認為大寫字母和小寫字母相同。網際網路名稱分配機構(IANA )維護所有正式註冊的字符集名稱。
public class EncodeTest { public static void main(String[] argv) throws Exception { // This is the character sequence to encode String input = " \u00bfMa\u00f1ana?"; // the list of charsets to encode with String[] charsetNames = { "US-ASCII", "ISO-8859-1", "UTF-8", "UTF-16BE", "UTF-16LE", "UTF-16" // , "X-ROT13" }; for (int i = 0; i < charsetNames.length; i++) { doEncode(Charset.forName(charsetNames[i]), input); } } /** * For a given Charset and input string, encode the chars and print out the * resulting byte encoding in a readable form. */ private static void doEncode(Charset cs, String input) { ByteBuffer bb = cs.encode(input); System.out.println("Charset: " + cs.name()); System.out.println(" Input: " + input); System.out.println("Encoded: "); for (int i = 0; bb.hasRemaining(); i++) { int b = bb.get(); int ival = ((int) b) & 0xff; char c = (char) ival; // Keep tabular alignment pretty if (i < 10) System.out.print(" "); // Print index number System.out.print(" " + i + ": "); // Better formatted output is coming someday... if (ival < 16) System.out.print("0"); // Print the hex value of the byte System.out.print(Integer.toHexString(ival)); // If the byte seems to be the value of a // printable character, print it. No guarantee // it will be. if (Character.isWhitespace(c) || Character.isISOControl(c)) { System.out.println(""); } else { System.out.println(" (" + c + ")"); } } System.out.println(""); } }
字元轉碼