1. 程式人生 > >Java 字符編碼 ASCII、Unicode和UTF-8

Java 字符編碼 ASCII、Unicode和UTF-8

之間 family 打印 com 但是 例如 進制數 英語 utf-16

  1 ASCII碼

  統一規定英語字符與二進制位之間的關系。ASCII碼一共規定了128個字符的編碼。例如,空格“SPACE”是32(二進制00100000),大寫字母A是65(二進制01000001)。這128個符號(包括32個不能打印出來的控制符號)只占用了一個字節的後面7位,最前面的1位統一規定為0。

  2 非ASCII編碼

  表示非英語的其他語言時,128個符號是不夠的。例如,在法語中,字母上方有註音符號,無法用ASCII碼表示。於是,一些歐洲國家就決定:利用字節中閑置的最高位編入新的符號。例如,法語中的é的編碼為130(二進制是10000010)。這樣可以表示256個符號。

  但是,不同的國家有不同的字母,因此,哪怕它們都使用256個符號的編碼方式,代表的字母卻不一樣。例如,130在法語編碼中代表é,在希伯來語編碼中代表字母Gimel (?),在俄語編碼中代表另一個符號。0-127表示的符號是一樣的,不一樣的是128-255這一段。

漢字多達10萬左右,需要使用多個字節表示一個漢字。例如,簡體中文常見的編碼方式是GB2312,使用兩個字節表示一個漢字,所以理論上最多可以表示256x256=65536個漢字。雖然都是用多個字節表示一個符號,但是GB類的漢字編碼與下面的Unicode和UTF-8是沒關系的。

  3 Unicode

  世界上存在多種編碼方式,同一個二進制數字可以被解釋成不同的符號。之所以電子郵件經常出現亂碼,是因為發信人和收信人使用的編碼方式不一樣。作為所有符號的編碼,Unicode納入了世界上所有的符號,給予每一個符號一個獨一無二的編碼。它是一個龐大的集合,可以容納100多萬個符號。例如,U+0639表示阿拉伯字母Ain,U+0041表示英語的大寫字母A,U+4E25表示漢字嚴。具體的符號對應表,可以查詢http://www.unicode.org/或者漢字對應表。

  Unicode的問題

  Unicode只是一個符號集,只規定了符號的二進制編碼,但沒有規定存儲方式。例如,漢字嚴的Unicode是十六進制數4E25,轉換成二進制數足足有15位(100111000100101)即需要2個字節。不同的符號需要的字節數量不同。存在如下2個問題:

  1 如何區別Unicode和ASCII?

  計算機怎麽知道3個字節表示一個符號,而不是分別表示3個符號呢?

  2 容易出現空間浪費

  英文字母僅需一個字節。如果Unicode統一規定每個符號用3個或4個字節表示,那麽存儲英文字母時會出現2個或3個字節全是0,浪費空間。

  於是,出現了Unicode的多種實現方式。

  4 UTF-8

  UTF-8是互聯網上使用最廣的一種Unicode實現方式。其他實現方式包括UTF-16(字符用2個字節或4個字節表示)和UTF-32(字符用4個字節表示)。UTF-8是一種可變長的編碼方式,使用1~4個字節表示一個符號,根據不同的符號調整字節數量。

  UTF-8的編碼規則:

  1 對於單字節的符號,字節的第一位設為0,後面7位是這個符號的Unicode編碼。因此,對於英語字母,UTF-8編碼和ASCII碼是相同的。

  2 對於n個字節的符號(n>1),第一個字節的前n位都設為1,第n+1位設為0,後面字節的前兩位均設為10。剩下的二進制位由這個符號的Unicode編碼從後向前依次填入,空位補0。

  編碼規則總結見下表,字母x表示可編碼的位:

  技術分享

  以漢字嚴為例,如何實現UTF-8編碼:

  已知嚴的Unicode是4E25(100111000100101),根據上表,4E25處在第3行的範圍內(0000 0800-0000 FFFF),所以嚴的UTF-8編碼需要3個字節,即格式是“1110xxxx 10xxxxxx 10xxxxxx”。然後,從嚴的最後一個二進制位開始,依次從後向前填入格式中的x,空位補0。於是,嚴的UTF-8編碼是“11100100 10111000 10100101”,轉換成十六進制是E4B8A5。

  參考資料

  字符編碼筆記:ASCII,Unicode和UTF-8

Java 字符編碼 ASCII、Unicode和UTF-8