參考:
https://blog.csdn.net/prdslf001001/article/details/78615823
https://www.cnblogs.com/yangxiaoqin/p/8460395.html
https://blog.csdn.net/junjianlee/article/details/1479930
https://blog.csdn.net/zhusongziye/article/details/84261211
位(bit)、字節(byte)、字符、編碼之間的關系
1、位:
數據存儲的最小單位。每個二進制數字0或者1就是1個位;
2、字節:
8個位構成一個字節;即:1 byte (字節)= 8 bit(位);
1 KB = 1024 B(字節);
1 MB = 1024 KB; (2^10 B)
1 GB = 1024 MB; (2^20 B)
1 TB = 1024 GB; (2^30 B)
3、字符:
a、A、中、+、*、の......均表示一個字符;
一般 utf-8 編碼下,一個漢字字符 占用 3 個 字節;
一般 gbk 編碼下,一個漢字 字符 占用 2 個 字節;
4、字符集:
即各種各個字符的集合,也就是說哪些漢字,字母(A、b、c)和符號(空格、引號..)會被收入標准中;
5、編碼:
規定每個“字符”分別用一個字節還是多個字節存儲,用哪些字節來存儲,這個規定就叫做“編碼”。(其實際是對字符集中字符進行編碼,即:每個字符用二進制在計算中表示存儲);
通俗的說:編碼就是按照規則對字符進行翻譯成對應的二進制數,在計算器中運行存儲,用戶看的時候(比如瀏覽器),在用對應的編碼解析出來用戶能看懂的;
(1)標准ASCii字符集:有96個打印字符,和32個控制字符組成;一共96+32=128個;
用7位二進制數來對每1個字符進行編碼;
而由於7位還還不夠1個字節,而電腦的內部常用字節來用處理,每個字節中多出來的最高位用0替代;
0 000 0000.........................0
0 111 1111..........................127; 從0----127,來表示128個ACSii編碼;
比如:字符 'A'----------在計算器內部用0100 0001 (65)來表示;
字符'a'-----------在計算器內部用0 110 0001 (97)來表示;
注意:'10'在計算器內部是沒有編碼的,因為它是字符串,而不是單個字符。可以分別對1,0字符編碼存儲;
(2)擴展ASCii字符集:將標准的ASCii最高位1,得到十進制代碼128---255(1 000 0000----1 111 1111);所以字符集一共有0---255, 256個字符;
(3)gb2312字符集: 所有漢字字符在計算機內部采用2個字節來表示,每個字節的最高位規定為1【正好與標准ASCii字符(最高位是0)不重疊,並兼容】,不支持繁體字;
所以:gb2312表示漢字的編碼為:[129--255][129--255] (兩個字節,每個字節最高位是1);小於127的字符,與ASCii編碼相同;
(4)gbk字符集:gb2312的擴充,兼容gb2312,除了收錄gb2312所有的字符外,還收錄了其他不常見的漢字、繁體字等;
gbk中字符是一個或兩個字節,單字節字符00--7F(0---127)這個區間和ASCII是一樣的;
雙字節字符的第一個字節是在81--FE(129--254)之間。通過這個可以判斷是單字節還是雙字節;
即:在gbk字符編碼,如果第一個字節是>128的,則再往后找一個字節,組成漢字;如果第一個字節<128,則表示的是一個單字節(此時和ASCII是一樣的);
(5)Unicode字符集:容納世界上所有語言字符和符號的集合;(以及對應的二進制數字);
Unicode只是一個編碼規范,目前實際實現的unicode編碼只要有三種:UTF-8,UCS-2和UTF-16,三種unicode字符集之間可以按照規范進行轉換。
(6)utf-8編碼:UTF-8(8-bit Unicode Transformation Format)是一種針對Unicode的可變長度字符編碼,也是一種前綴碼。它可以用來表示Unicode標准中的任何字符,且其編碼中的第一個字節仍與ASCII兼容,這使得原來處理ASCII字符的軟件無須或只須做少部分修改,即可繼續使用。因此,它逐漸成為電子郵件、網頁及其他存儲或發送文字的應用中,優先采用的編碼。
對於UTF-8編碼中的任意字節B,如果B的第一位為0,則B獨立的表示一個字符(ASCII碼);
如果B的第一位為1,第二位為0,則B為一個多字節字符中的一個字節(非ASCII字符);
如果B的前兩位為1,第三位為0,則B為兩個字節表示的字符中的第一個字節;
如果B的前三位為1,第四位為0,則B為三個字節表示的字符中的第一個字節;
如果B的前四位為1,第五位為0,則B為四個字節表示的字符中的第一個字節;
因此,對UTF-8編碼中的任意字節,根據第一位,可判斷是否為ASCII字符;根據前二位,可判斷該字節是否為一個字符編碼的第一個字節;根據前四位(如果前兩位均為1),可確定該字節為字符編碼的第一個字節,並且可判斷對應的字符由幾個字節表示;根據前五位(如果前四位為1),可判斷編碼是否有錯誤或數據傳輸過程中是否有錯誤。
即:
1、單字節的字符,字節的第一位設為0,對於英語文本,UTF-8碼只占用一個字節,和ASCII碼完全相同;
2、n個字節的字符(n>1),第一字節的前n位設為1,第n+1位設為0,后面字節的前兩位都設為10;
3、2個字節,第一個字節的前2位是1;3個字節,第一個字節的前三位是1; 4個字節,第一個字節的前4位都是1;
位、字節、字符的區別
位(bit):是計算機 內部數據 儲存的最小單位,11001100是一個八位二進制數。
字節(byte):是計算機中 數據處理 的基本單位,習慣上用大寫 B 來表示,1B(byte,字節)= 8bit(位)
字符:是指計算機中使用的字母、數字、字和符號
ASCIIS碼: 1個英文字母(不分大小寫)= 1個字節的空間
1個中文漢字 = 2個字節的空間
1個ASCII碼 = 一個字節
UTF-8編碼:1個英文字符 = 1個字節
英文標點 = 1個字節
1個中文(含繁體) = 3個字節
中文標點 = 3個字節
Unicode編碼:1個英文字符 = 2個字節
英文標點 = 2個字節
1個中文(含繁體) = 2個字節
中文標點 = 2個字節
Unicode字符是什么?
Unicode 是一種重要的交互和顯示的通用字符編碼標准,它覆蓋了美國、歐洲、中東、非洲、印度、亞洲和太平洋的語言,以及古文和專業符號。Unicode 允許交換、處理和顯示多語言文本以及公用的專業和數學符號。它希望能夠解決多語言的計算,如不同國家的字符標准,但並不是所有的現代或古文都能夠獲得支持。
Unicode 字符可以適用於所有已知的編碼。Unicode 是繼 ASCII(美國國家交互信息標准編碼)字符碼后的一種新字符編碼,它為每一個符號定義一個數字和名稱,並指定字符和它的數值(碼位),以及該值的二進制位表示法,通過一個十六進制數字和前綴(U)定義一個16位的數值,如:U+0041 表示 A,其唯一的名稱是 LATIN CAPITAL LETTER A。但請注意:JavaScript 1.3 之前的版本並不支持 Unicode 編碼。
Unicode 與 ASCII 和 ISO 的兼容性
Unicode 兼容於 ASCII 字符並被大多數程序所支持,前128個 Unicode 碼同 ASCII 碼具有同樣的字節值;Unicode 字符從 U+0020 到 U+007E 等同與 ASCII 碼的 0x20 到 0x7E,不同於支持拉丁字母的7位 ASCII,Unicode 對每個字符進行16位值的編碼設置,它允許幾萬個字符,例如 Unicode 2.0 版包含 38,885 個字符,它也可以進行擴展,如 UTF-16 允許用16位字符組合為一百萬或更多的字符,UTF 將編碼轉換為真實的二進制位。
Unicode 完全兼容於國際標准 ISO/IEC 10646-1; 1993,它是 ISO 10646 的一個子集,並支持用兩個八進制數的 ISO UCS-2(Universal Character Set)。JavaScript 1.3 版本對 Unicode 的支持意味着您可以任意地在程序中使用本地的字符以及特殊的科學符號。Unicode 提供了一種標准的方法來編碼多語言文本,並且因為它兼容於 ASCII ,您也可以隨意使用 ASCII 字符。
您可以在不同的語言中使用 Unicode 來顯示字符或專業符號,但這需要一個客戶端能夠支持 Unicode,例如 Netscape Navigator 4.x,並且客戶端還得支持 Unicode 字體以及操作平台的支援。例如 Windows 95 它只支持部分的 Unicode,另外,為了輸入非 ASCII 字符,您還得有支持所有 Unicode 字符的輸入設備,一個標准的擴展鍵盤不能夠做到這一點,但我們可以用 Unicode 轉義序列來輸入 Unicode 字符。如果您還需了解 Unicode 更多的信息,請參見 Unicode Consortium Web site 2.0版
http://www.unicode.org/和http://charts.unicode.org/中發現在線信息。表7-6列出了由Unicode編碼的文字,由此可知Unicode的廣泛性。每一種文字的字符通常編碼在65,536個號碼中的一個連續區域內。許多語言都能使用其中某一區域的字符書寫(例如,使用古斯拉夫語書寫俄語),盡管有一些語言,如克羅地亞語或土耳其語需要混合匹配前4個拉丁文區域中的字符。
UTF-8
Unicode使用雙字節表示一個字符,因此使用Unicode的英文文本文件大小是使用ASCII碼或Latin-1文件的兩倍。UTF-8是一個壓縮的Unicode版本,使用單個字節表示最常用的字符,即0到127的ASCII字符,較少見的字符使用三個字節表示,特制是韓國音節和漢字。如果主要使用英文,UTF-8能夠將文件壓縮為原來的一半。如果主要使用漢語、朝語或者日語,UTF-8會使文件的尺寸增加50%��因此應當謹慎使用UTF-8。UTF-8幾乎不能處理非羅馬文字和非CJK文字,如希臘語、阿拉伯語、古斯拉夫語和希伯來語。
XML處理器在沒有被預先通知的情況下假定文本數據是UTF-8格式。這意味着XML處理器能夠閱讀ASCII碼文件,但是使用它處理其他格式的文件像MacRoman 或者 Latin-1會有困難。我們很快就能學會如何在短時間內解決這個問題。
通用字符系統
Unicode因為沒有包含足夠多的語言和文字而受到批評,特別是亞洲東部的語言。它只定義了中國、日本、朝鮮和古越南使用的80,000象形文字中的20,000個左右。(現代越南語使用一種羅馬字母。)
UCS (Universal Character System)��通用字符系統,也稱作ISO 10646,使用四個字節(確切地說是31位)表示一個字符,以給20多億不同的字符提供足夠的空間。這樣能容易地覆蓋地球上任何一種文字和語言使用的每個字符。而且還可以給每一種語言指定一個完整的字符集,使法語中的“e”不同於英語和德語中的“e”等等。
與Unicode一樣,UCS定義了許多不同的變種和壓縮形式。純粹的Unicode有時指USC-2,是雙字節的UCS。UTF-16是一種特別的編碼,它把一些UCS字符安排在長度變化的字符串中,在這種方式下Unicode(UCS-2)數據不會改變。
UCS超越Unicode的優點主要是理論方面的。在UCS中實際定義過的字符就是Unicode中已有的字符。但是UCS為以后的字符擴充提供了更多的空間。
1. 不同時引用多種文字。
2. 不與使用不同字符集的人交換文件。
由於Mac和PC機都使用不同的字符集,越來越多的人無法遵循以上原則。很明顯的是需要一種得到大家的認可並且編碼了全世界各種文字的字符集。建立這樣的字符集很難,需要對成百上千種語言和文字有細致的了解。要使軟件開發商們同意使用這種字符集就更難了。不過這方面的努力一直在進行,終於創建了一個符合要求的字符集��Unicode。而且主要賣方(微軟、蘋果、IBM、Sun、Be等)正逐步趨向於使用它。XML把Unicode當作自己的默認字符集。
Unicode使用0~65,535的雙字節無符號數對每一個字符進行編碼。目前已經定義了40,000多個不同的Unicode字符,剩余25,000個空缺留給將來擴展之用。其中大約20,000個字符用於漢字,另外11,000左右的字符用於韓語音節。Unicode中0~`255的字符與Latin-1中的一致。
如果在本書中顯示所有的Unicode字符,那么除了這些字符表格外,書中將容納不下別的任何東西。如果需要知道Unicode中不同字符的確定編碼,買一冊Unicode標准(第二版,ISBN 0-201-48346-9,Addison-Wesley出版)。該書共950頁,包括對Unicode 2.0的全部詳細說明,還包括Unicode 2.0中定義的所有字符集的圖表。還可以在Unicode協會的網址:
Unicode 和 UTF-8 是什么關系
想必做過爬蟲的同學肯定被編碼問題困擾過,有 UTF-8、GBK、Unicode 等等編碼方式,但你真的了解其中的原理嗎?下面我們就來了解一下 Unicode 和 UTF-8 編碼到底有什么關系。
要弄清 Unicode 與 UTF-8 的關系,我們還得從他們的來源說起,下來我們從剛開始的編碼說起,直到 Unicode 的出現,我們就會感覺到他們之間的關系
ASCII碼
我們都知道,在計算機的世界里,信息的表示方式只有 0 和 1,但是我們人類信息表示的方式卻與之大不相同,很多時候是用語言文字、圖像、聲音等傳遞信息的。
那么我們怎樣將其轉化為二進制存儲到計算機中,這個過程我們稱之為編碼。更廣義地講就是把信息從一種形式轉化為另一種形式的過程。
我們知道一個二進制有兩種狀態:”0” 狀態 和 “1”狀態,那么它就可以代表兩種不同的東西,我們想賦予它什么含義,就賦予什么含義,比如說我規定,“0” 代表 “吃過了”, “1”代表 “還沒吃”。
這樣,我們就相當於把現實生活中的信息編碼成二進制數字了,並且這個例子中是一位二進制數字,那么 2 位二進制數可以代表多少種情況能?對,是四種,2^2,分別是 00、01、10、11,那 7 種呢?答案是 2^7=128。
我們知道,在計算機中每八個二進制位組成了一個字節(Byte),計算機存儲的最小單位就是字節,字節如下圖所示 :
所以早期人們用 8 位二進制來編碼英文字母(最前面的一位是 0),也就是說,將英文字母和一些常用的字符和這 128 中二進制 0、1 串一一對應起來,比如說 大寫字母“A”所對應的二進制位“01000001”,轉換為十六進制為 41。
在美國,這 128 是夠了,但是其他國家不答應啊,他們的字符和英文是有出入的,比如在法語中在字母上有注音符號,如 é ,這個怎么表示成二進制?
所以各個國家就決定把字節中最前面未使用的那一個位拿來使用,原來的 128 種狀態就變成了 256 種狀態,比如 é 就被編碼成 130(二進制的 10000010)。
為了保持與 ASCII 碼的兼容性,一般最高為為 0 時和原來的 ASCII 碼相同,最高位為 1 的時候,各個國家自己給后面的位 (1xxx xxxx) 賦予他們國家的字符意義。
但是這樣一來又有問題出現了,不同國家對新增的 128 個數字賦予了不同的含義,比如說 130 在法語中代表了 é,但是在希伯來語中卻代表了字母 Gimel(這不是希伯來字母,只是讀音翻譯成英文的形式)具體的希伯來字母 Gimel 看下圖
所以這就成了不同國家有不同國家的編碼方式,所以如果給你一串二進制數,你想要解碼,就必須知道它的編碼方式,不然就會出現我們有時候看到的亂碼 。
Unicode的出現
Unicode 為世界上所有字符都分配了一個唯一的數字編號,這個編號范圍從 0x000000 到 0x10FFFF (十六進制),有 110 多萬,每個字符都有一個唯一的 Unicode 編號,這個編號一般寫成 16 進制,在前面加上 U+。例如:“馬”的 Unicode 是U+9A6C。
Unicode 就相當於一張表,建立了字符與編號之間的聯系
它是一種規定,Unicode 本身只規定了每個字符的數字編號是多少,並沒有規定這個編號如何存儲。
有的人會說了,那我可以直接把 Unicode 編號直接轉換成二進制進行存儲,是的,你可以,但是這個就需要人為的規定了,而 Unicode 並沒有說這樣弄,因為除了你這種直接轉換成二進制的方案外,還有其他方案,接下來我們會逐一看到。
編號怎么對應到二進制表示呢?有多種方案:主要有 UTF-8,UTF-16,UTF-32。
1、UTF-32
先來看簡單的 UTF-32
這個就是字符所對應編號的整數二進制形式,四個字節。這個就是直接轉換。 比如馬的 Unicode 為:U+9A6C,那么直接轉化為二進制,它的表示就為:1001 1010 0110 1100。
這里需要說明的是,轉換成二進制后計算機存儲的問題,我們知道,計算機在存儲器中排列字節有兩種方式:大端法和小端法,大端法就是將高位字節放到底地址處,比如 0x1234, 計算機用兩個字節存儲,一個是高位字節 0x12,一個是低位字節 0x34,它的存儲方式為下:
UTF-32 用四個字節表示,處理單元為四個字節(一次拿到四個字節進行處理),如果不分大小端的話,那么就會出現解讀錯誤,比如我們一次要處理四個字節 12 34 56 78,這四個字節是表示 0x12 34 56 78 還是表示 0x78 56 34 12?不同的解釋最終表示的值不一樣。
我們可以根據他們高低字節的存儲位置來判斷他們所代表的含義,所以在編碼方式中有 UTF-32BE 和 UTF-32LE,分別對應大端和小端,來正確地解釋多個字節(這里是四個字節)的含義。
2、UTF-16
UTF-16 使用變長字節表示
① 對於編號在 U+0000 到 U+FFFF 的字符(常用字符集),直接用兩個字節表示。
② 編號在 U+10000 到 U+10FFFF 之間的字符,需要用四個字節表示。
同樣,UTF-16 也有字節的順序問題(大小端),所以就有 UTF-16BE 表示大端,UTF-16LE 表示小端。
3、UTF-8
UTF-8 就是使用變長字節表示,顧名思義,就是使用的字節數可變,這個變化是根據 Unicode 編號的大小有關,編號小的使用的字節就少,編號大的使用的字節就多。使用的字節個數從 1 到 4 個不等。
UTF-8 的編碼規則是:
① 對於單字節的符號,字節的第一位設為 0,后面的7位為這個符號的 Unicode 碼,因此對於英文字母,UTF-8 編碼和 ASCII 碼是相同的。
② 對於n字節的符號(n>1),第一個字節的前 n 位都設為 1,第 n+1 位設為 0,后面字節的前兩位一律設為 10,剩下的沒有提及的二進制位,全部為這個符號的 Unicode 碼 。
舉個例子:比如說一個字符的 Unicode 編碼是 130,顯然按照 UTF-8 的規則一個字節是表示不了它(因為如果是一個字節的話前面的一位必須是 0),所以需要兩個字節(n = 2)。
根據規則,第一個字節的前 2 位都設為 1,第 3(2+1) 位設為 0,則第一個字節為:110X XXXX,后面字節的前兩位一律設為 10,后面只剩下一個字節,所以后面的字節為:10XX XXXX。
所以它的格式為 110XXXXX 10XXXXXX 。
下面我們來具體看看具體的 Unicode 編號范圍與對應的 UTF-8 二進制格式
那么對於一個具體的 Unicode 編號,具體怎么進行 UTF-8 的編碼呢?
首先找到該 Unicode 編號所在的編號范圍,進而可以找到與之對應的二進制格式,然后將該 Unicode 編號轉化為二進制數(去掉高位的 0),最后將該二進制數從右向左依次填入二進制格式的 X 中,如果還有 X 未填,則設為 0 。
比如:“馬”的 Unicode 編號是:0x9A6C,整數編號是 39532,對應第三個范圍(2048 - 65535),其格式為:1110XXXX 10XXXXXX 10XXXXXX,39532 對應的二進制是 1001 1010 0110 1100,將二進制填入進入就為:
11101001 10101001 10101100 。
由於 UTF-8 的處理單元為一個字節(也就是一次處理一個字節),所以處理器在處理的時候就不需要考慮這一個字節的存儲是在高位還是在低位,直接拿到這個字節進行處理就行了,因為大小端是針對大於一個字節的數的存儲問題而言的。
綜上所述,UTF-8、UTF-16、UTF-32 都是 Unicode 的一種實現。