快速學會區分“字符集”與“字符編碼”——附:內碼與外碼區別


一、引言

  日常復習總結,發現太久不看基礎,很多概念的東西還是給忘了,本文將教你如何快速區分“字符”與“字符集”。

二、基礎知識

2.1 字符

  各種文字和符號的總稱,包括各國家文字、標點符號、圖形符號、數字等。 也就是說,它是一個信息單位,一個數字是一個字符,一個文字是一個字符,一個標點符號也是一個字符。

2.2 字節

  字節是一個8bit的存儲單元,取值范圍是0x00~0xFF。 根據字符編碼的不同,一個字符可以是單個字節的,也可以是多個字節的。

2.3 字符集

  字符的集合就叫字符集。不同集合支持的字符范圍自然也不一樣,譬如ASCII只支持英文,GB18030支持中文等等。

  在字符集中,有一個碼表的存在,每一個字符在各自的字符集中對應着一個唯一的碼。但是同一個字符在不同字符集中的碼是不一樣的,譬如字符“中”在Unicode和GB18030中就分別對應着不同的碼(2001354992)。

  簡單來說,字符集就是一個按規則排列的字符的集合,可以理解為現實生活中的各種“字典”。例如:牛津字典,劍橋商務字典等等。同一個“單詞”在不同的字典中的位置是不同的,同理也不是所有的字典都支持各種語言的,例如ASCLL字符集里面就沒有中文。

2.4 字符編碼

  定義字符集中的字符如何編碼為特定的二進制數,以便在計算機中存儲(就是將字符在字符集中的對應位置化為二進制)。字符集和字符編碼一般一一對應(也有例外)

  字符集與字符編碼的一個例外就是Unicode字符集,它有多種編碼實現(UTF-8,UTF-16,UTF-32等)

三、舉例理解

  其實通過上面的標藍的句子相信大家已經有了區分的理解。下面再舉出一些例子,來加深大家的理解:

  • ASCII碼是一個字符集,同時它的實現也只有一種,因此它也可以指代這個字符集對應的字符編碼。

  • GB18030是一個字符集,主要是中國人為了解決中文而發明制定的,由於它的實現也只有一種,所以它也可以指代這個字符集對應的字符編碼。

  • Unicode是一個字符集(java默認),為了解決不同字符集碼表不一致而推出的,統一了所有字符對應的碼,因此在這個規范下,所有字符對應的碼都是一致的(統一碼),但是統一碼只規定了字符與碼表的一一對應關系,卻沒有規定該如何實現,因此這個字符集有多種實現方式(UTF-8,UTF-18,UTF-32),因此這些實現就是對應的字符編碼。 也就是說,Unicode統一約定了字符與碼表直接一一對應的關系,而UTF-8是Unicode字符集的一種字符編碼實現方式,它規定了字符該如何編碼成二進制,存儲在計算機中。

 

附:常用編碼表

  ISO8859-1 GBK/GBK2312 UTF-8 UTF-16 UTF-32
英文字符 1字節 2字節 大部分3,少部分4 2字節 4字節
中文字符 1字節 1字節 1字節 2字節 4字節

  如表所示,ISO8859-1、utf-16、utf-32都是定長字符編碼,其中utf-16(Unicode)更是jvm默認的內碼編碼。

內碼 vs 外碼 

  java在內部都是unicode編碼,不存在什么GBK/UTF-8只有在輸入輸出的時候,才會發生與外部的編碼轉化問題。

  簡單來說,內碼:char或String在內存里使用的編碼方式。

       外碼:除了內碼都可以認為是“外碼”。(包括class文件的編碼)

java內碼:unicode(utf-16)

jvm默認外碼:windows——gbk

     Linux——utf-8

外碼操作:

[String].getBytes() 就是將內碼轉換成外碼存儲在byte數組里,方法有兩種形式:

  • getBytes(String charsetName): 使用指定的字符集將字符串編碼為 byte 序列,並將結果存儲到一個新的 byte 數組中。

  • getBytes(): 使用平台的默認字符集將字符串編碼為 byte 序列,並將結果存儲到一個新的 byte 數組中。

new String(byte[] bytes, String charset): 將字符序列bytes使用“charset”的字符編碼(外碼),解碼成字符串(內碼)

  編碼和解碼的“字符編碼”必須要一致才能解碼成想要的字符串(英文例外)。

 

但是為什么在tomcat 下,使用 new String(s.getBytes("iso-8859-1") ,"GBK") 卻可以用呢? 答案是:

  tomcat 默認使用iso-8859-1編碼, 也就是說,如果原本字符串 str 是GBK的,tomcat傳輸過程中,將GBK轉成iso-8859-1編碼的字符數組了,相當於:

String s = "中國";
byte[] str_bytes = s.getBytes("GBK"); // 底層操作1:jvm,此時編碼格式為gbk; String s = new String(str_bytes, "iso-8859-1"); // 底層操作2:tomcat; String str_new =new String(s.getBytes( "iso-8859-1"), "gbk"); // 得到正確字符串

  默認情況下,使用iso-8859-1讀取中文肯定是有問題的,那么我們需要將iso-8859-1 再轉成GBK, 而iso-8859-1 是單字節編碼的,即他認為一個字節是一個字符, 那么這種轉換不會對原來的字節數組做任何改變,因為字節數組本來就是由單個字節組成的,如果之前用GBK編碼,那么轉成iso-8859-1后編碼內容完全沒變, 則 s.getBytes("iso-8859-1")  實際上還是原來GBK的編碼內容則 new String(s.getBytes("iso-8859-1") ,"GBK")  就可以正確解碼了。 所以說這是一種特殊情況。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM