字符編碼
1. 基礎知識
字符集(Charset):是一個係統支持的所有抽象字符的集合。字符是各種文字和符號的總稱,包括各國家文字、標點符號、圖形符號、數字等。
字符編碼(Character Encoding):是一套法則,使用該法則能夠對自然語言的字符的一個集合(如字母表或音節表),與其他東西的一個集合(如號碼或電脈衝)進行配對
2.常用字符集
上個世紀60年代,美國製定了一套字符編碼,對英語字符與二進製位之間的關係,做了統一規定。這被稱為ASCII碼,一直沿用至今。
ASCII碼一共規定了128個字符的編碼,比如空格“SPACE”是32(二進製00100000),大寫的字母A是65(二進製01000001)。這128個符號(包括32個不能打印出來的控製符號),隻占用了一個字節的後麵7位,最前麵的1位統一規定為0
在計算機科學領域中,Unicode(統一碼、萬國碼、單一碼、標準萬國碼)是業界的一種標準,它可以使電腦得以體現世界上數十種文字的係統。Unicode 是基於通用字符集(Universal Character Set)的標準來發展,並且同時也以書本的形式[1]對外發表。Unicode 還不斷在擴增, 每個新版本插入更多新的字符。直至目前為止的第六版,Unicode 就已經包含了超過十萬個字符(在2005年,Unicode 的第十萬個字符被采納且認可成為標準之一)、一組可用以作為視覺參考的代碼圖表、一套編碼方法與一組標準字符編碼、一套包含了上標字、下標字等字符特性的枚舉等。Unicode 組織(The Unicode Consortium)是由一個非營利性的機構所運作,並主導 Unicode 的後續發展。
UTF-32:
使用4字節的數字來表達每個字母、符號,或者表意文字(ideograph),每個數字代表唯一的至少在某種語言中使用的符號的編碼方案,稱為UTF-32。UTF-32又稱UCS-4是一種將Unicode字符編碼的協定,對每個字符都使用4字節。就空間而言,是非常沒有效率的,不被使用。
UTF-16:
盡管有Unicode字符非常多,但是實際上大多數人不會用到超過前65535個以外的字符。因此,就有了另外一種Unicode編碼方式,叫做UTF-16(因為16位
= 2字節)。UTF-16將0–65535範圍內的字符編碼成2個字節.
對於UTF-16編碼,不同計算機以不同順序保存字節。這意味著字符U+4E2D在UTF-16編碼方式下可能被保存為4E
2D或者2D 4E,這取決於該係統使用的是大尾端(big-endian)還是小尾端(little-endian)
UTF-8:
UTF-8 is a variable-width encoding that can represent every character in the Unicode character set. It was designed for backward compatibility with ASCII and to avoid the complications of endianess and byte order marks in UTF-16 and UTF-32.
互聯網的普及,強烈要求出現一種統一的編碼方式。UTF-8就是在互聯網上使用最廣的一種unicode的實現方式。其他實現方式還包括UTF-16和UTF-32,不過在互聯網上基本不用。重複一遍,這裏的關係是,UTF-8是Unicode的實現方式之一。
UTF-8最大的一個特點,就是它是一種變長的編碼方式。它可以使用1~4個字節表示一個符號,根據不同的符號而變化字節長度。
UTF-8的編碼規則很簡單,隻有二條:
1)對於單字節的符號,字節的第一位設為0,後麵7位為這個符號的unicode碼。因此對於英語字母,UTF-8編碼和ASCII碼是相同的。
2)對於n字節的符號(n>1),第一個字節的前n位都設為1,第n+1位設為0,後麵字節的前兩位一律設為10。剩下的沒有提及的二進製位,全部為這個符號的unicode碼。
下表總結了編碼規則,字母x表示可用編碼的位。
Unicode符號範圍 | UTF-8編碼方式
(十六進製) | (二進製)
--------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
下麵,還是以漢字“嚴”為例,演示如何實現UTF-8編碼。
已知“嚴”的unicode是4E25(100111000100101),根據上表,可以發現4E25處在第三行的範圍內(0000 0800-0000 FFFF),因此“嚴”的UTF-8編碼需要三個字節,即格式是“1110xxxx 10xxxxxx 10xxxxxx”。然後,從“嚴”的最後一個二進製位開始,依次從後向前填入格式中的x,多出的位補0。這樣就得到了,“嚴”的UTF-8編碼是“11100100 10111000 10100101”,轉換成十六進製就是E4B8A5。
3. Java中字符編碼。
3.1 Char to Byte & Byte to Char
public static void charTest() throws Exception{ //char: The char data type is a single 16-bit Unicode character. It has a minimum value of '\u0000' (or 0) and a maximum value of '\uffff' (or 65,535 inclusive). char c = '\u4E25'; System.out.println("Unicode to char : "+c); byte[] cb = new byte[2]; cb[0] = (byte) ((c&0xFF00)>>8); //取高8位 cb[1] = (byte) (c&0x00FF); // 取低8位 System.out.println("Byte[0] is 0x4E?: " + (cb[0] == 0x4E)+" --- Byte[1] is 0x25?: "+ (cb[1]==0x25)); System.out.println(new String(cb,"Unicode")); System.out.println(new String(cb,"utf8"));//亂碼,因為編碼是unicode,解碼是utf8 byte[] ba = new byte[3];//E4B8A5 是‘嚴’的 UTF8編碼,三個byte ba[0]=(byte)0xE4; ba[1]=(byte)0xB8; ba[2]=(byte)0xA5; System.out.println("UTF8 encoding 3 bytes to chinese character: "+new String(ba,"utf8")); c = 'a'; System.out.println("ASCII code of print char : " + (byte)c); c = '\n'; System.out.println("ASCII code of ctrl char : " + (byte)c); }
3.2 Variable-width encoding UTF8
//UTF8 是變長的編碼 public static void UTF8Test() throws Exception{ String s = "人們"; System.out.print("Encoded by GBK : "); displayByteArr(s.getBytes("GBK")); System.out.print("Encoded by UTF8 : ");//一個漢字 占3個byte displayByteArr(s.getBytes("UTF8")); s = "ab"; System.out.print("Encoded by UTF8 : ");//一個英文字母 占1個byte displayByteArr(s.getBytes("UTF8")); System.out.print("Encoded by ASCII : ");//UTF8 對ASCII兼容,英文字母編碼相同 displayByteArr(stringToBytesASCII(s)); System.out.print("Encoded by UTF32 : ");//UTF32對任何字符都用4字節,空間浪費嚴重 displayByteArr(s.getBytes("UTF32")); } public static void displayByteArr(byte[] ba){ for (byte b : ba){ System.out.print(b+" "); } System.out.println(""); } public static byte[] stringToBytesASCII(String str) { char[] buffer = str.toCharArray(); byte[] b = new byte[buffer.length]; for (int i = 0; i < b.length; i++) { b[i] = (byte) buffer[i]; } return b; }
參考:
https://www.cnblogs.com/skynet/archive/2011/05/03/2035105.html#_4.Accept-Charset/Accept-Encoding/Ac
https://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
https://en.wikipedia.org/wiki/UTF-8
https://www.javacodegeeks.com/2010/11/java-best-practices-char-to-byte-and.html
最後更新:2017-04-04 07:03:03