作為一個程式設計師,告訴你一些編碼知識
計算機只認 0 和 1 ,所有的影像和字元最終都會轉換成計算機能夠認識的二進位制。一個二進位制位(bit)可以表示兩種狀態 0 和 1 ,一個位元組(byte)由八個二進位制位組成,所以一個位元組一共可以表示256( 2^8 )種狀態。 |
在諜戰劇裡,我們經常看到這樣一個橋段,特工人員,千辛萬苦拿到一條資訊,開啟一看是一串數字,然後趕緊跑到一個秘密地方,拿出一個密碼本(也可能是一本唐詩選),按照一定規則(只有自己人知道),比如第一個數字表示頁數,第二個數字表示行數,第三個數字表示第幾個字,逐一將資訊翻譯出來。如果這個過程中用了錯誤的密碼本,或者不知道規則,那麼將會解碼失敗。
計算機的編解碼過程跟上面的過程是一樣一樣的。
計算機只認 0 和 1 ,所有的影像和字元最終都會轉換成計算機能夠認識的二進位制。一個二進位制位(bit)可以表示兩種狀態 0 和 1 ,一個位元組(byte)由八個二進位制位組成,所以一個位元組一共可以表示256( 2^8 )種狀態。如果我們規定每種狀態代表一個字元,那麼一個位元組就可以表達出 256 個字元。
計算機是由美國人發明的,所以在最初設計編碼的時候,就只考慮了英文的編碼。英文字元很少,加上一些特殊字元,一共也就100個左右,確切的說是128個。這樣的話用一個位元組進行編碼就完全夠了,不僅夠用了,而且還富裕出一位,即第一位一直沒有參與編碼,統一定為 0 。這就是所謂的 ASCII 編碼。在 ASCII 編碼中,空格 SPACE 是 32 (二進位制 00100000 ),大寫的字母 A 是 65 (二進位制 01000001 )。
隨著計算機的普及,歐洲也開始普及計算機,歐洲人發現 ASCII 規定的 128 個字元不能滿足他們的使用,比如,在法語中,字母上方有注音符號,就無法用 ASCII 碼錶示。於是,一些歐洲國家就決定,把位元組中閒置的第一位編入新的符號。比如,法語中的 é 的編碼為 130 (二進位制 10000010 )。這樣一來,這些歐洲國家使用的編碼體系,最多可以表示 256 個符號。這就是大家經常見到的 ISO-8859-1 編碼,也叫 Latin1 編碼。
隨著計算機的普及,國人也開始使用計算機,但是發現按照之前的編碼方式,根本就沒有漢字什麼事兒,也就是計算機根本沒辦法認識漢字。
為了能夠讓計算機認識漢字,我們決定對漢字進行編碼,本著敢想敢幹的精神,我們規定用兩個位元組表示一個漢字。
具體規則是這樣的:一個小於 127 的位元組代表的意義與原來的 ASCII 相同,但兩個大於 127的位元組連在一起時,就表示這是一個漢字,前面的一個位元組稱為高位元組,後面一個位元組稱為低位元組,這樣我們就可以組合出 6763 個簡體漢字。這就是大家常說的 GB2312 編碼。
很顯然 GB2312 編碼的 6763 個漢字,並不能適應所有的使用場景,比如“喆”字就不再其中,於是在 GB2312 的基礎上又進行了新的擴充套件,規定只要第一個位元組是大於 127 的就OK,至於第二個位元組是大於 127 還是小於 127 都無所謂了。經過這樣的改動之後,收錄的漢字及符號就可以達到 2W 多個,這就是我們常說的 GBK 編碼。
再後來,人們繼續對第二個位元組進行擴充套件,發展出了 GB18030 編碼,比 GBK 又多出了一些字元編碼。
至此,所有的漢字編碼都是用兩個位元組表示的,但是英文是用一個位元組表示。上了一些年紀的程式設計師都體驗過,一個漢字算兩個英文字元的經歷。
上面提到的都是簡體中文編碼,雖然 GBK 及 GB18030 包含了部分繁體字,但是也不全面,於是臺灣同胞就發了專門支援繁體字的 Big5 編碼,也就是大家經常說的大五碼。
不知道大家有沒有注意到一個問題,在單位元組編碼的時候,對於那些大於 127 小於 256 的編碼,在不同的國家代表的字母很可能不一樣。比如, 130 在法語編碼中代表了 é ,在希伯來語編碼中卻代表了字母 Gimel (ג) ,在俄語編碼中又會代表另一個符號。在漢字的雙位元組編碼中也存在這樣的問題,比如 BIG5 編碼跟 GBK 編碼都是雙位元組編碼,但是代表的漢字卻不一樣。
這就相當於,同樣一串二進位制數值,A特工組織按照他們的規則解析出來可能是“你好”,而B特工組織按照他們的規則解析出來可能是“滾蛋”。特工組織之間的翻譯標準不一樣是相當有必要的,但是計算機的編碼規則如果各不相同就比較麻煩了。比如你跟臺灣的志玲姐姐聊天,志玲姐姐用 BIG5 編碼給你發了一封信,然後你用 GBK 去解碼,……,也許就沒有然後了。
為了解決上面的問題,有個叫 ISO 的國際標準組織,決定放棄所有區域性編碼,如 BIG5 , GBK 等,重新制定一個新的編碼,這個編碼集將包含所有字元的編碼,這樣大家就都統一了,這套編碼的英文全稱“Universal Multiple-Octet Coded Character Set”,簡稱UCS, 俗稱 “Unicode“。 Unicode 的出現相當於秦始皇對度量衡跟貨幣進行了統一。
Unicdoe 按照日常字元的使用頻繁度劃分了 17 個平面,編號為 0-16 , 0 號平面稱為基本多語言平面(Basic Multilingual Plane,簡稱 BMP ),包含了日常使用最頻繁的字元,編碼範圍從 0000 到 FFFF ,這樣該平面可以表示 2^16=65536 個字元;其它平面的編碼範圍也是從 0000 到 FFFF ,所以其它平面也可以編碼 65535 個字元,這樣 17 個平面一共可以編碼 17×65,536 = 1,114,112 個符號。
我們最常用的 Unicode 編碼使用的是多語言平面的編碼,即所有字元都用兩個位元組進行編碼(其它平面可能需要三個或四個位元組)。舉個例子比如中國的'中'字 Unicode 碼是 4E2D ,小寫'a'的 Unicode 碼是 0061 .
這裡面存在兩個問題,如果所有英文字元都是按照 Unicode 編碼,那麼會出現浪費儲存空間的問題。明明一個位元組可以搞定的事情,偏偏要用兩個位元組。
第二個問題就是計算機如何知道這是 Unicode 編碼還是 ASCII 編碼,也就是 2 個位元組表示的一個字元,還是 2 個字元呢。
UTF 的全稱是 Unicode Transformation Format ,也就是 Unicode 的轉換格式。上面提到了,如果直接使用 Unicode 碼進行儲存會存在浪費空間的問題,而 UTF-8 的出現就是為了解決該問題, UTF-8 使用變長的方式儲存 Unicode 碼,也就是英文字元繼續使用一個位元組進行儲存,但是漢字要使用 3 個位元組。那麼 UTF-8 是如何做到的呢。
首先,對於單位元組的符號,位元組的第一位設為 0 ,後面 7 位為這個符號的 Unicode 碼。因此對於英語字母, UTF-8 編碼和 ASCII 碼是相同的。
其次,對於 n 位元組的符號( n > 1 ),第一個位元組的前 n 位都設為 1 ,第 n + 1 位設為 0 ,後面位元組的前兩位一律設為 10 。剩下的沒有提及的二進位制位,全部為這個符號的 Unicode碼。
下表總結了編碼規則,字母 x 代表可用的編碼位。
Unicode符號範圍(十六進位制) UTF-8編碼方式(二進位制)<>pre
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 編碼進行解讀會發現,如果一個位元組的第一位是 0 ,則這個位元組單獨就是一個字元;如果第一位是 1 ,則連續有多少個 1 ,就表示當前字元佔用多少個位元組。
假設“hello世界”這樣一個字串,他們的 Unicode 的編碼分別是
1h--0068 2e--0065 3l--006C 4l--006C 5o--006F 6世--4E16 7界--754C
按照 UTF-8 的編碼規則可以得到如下 UTF-8 編碼
1h--01101000 2e--01100101 3l--01101100 4l--01101100 5o--01101111 6世--11100100-10111000-10010110 7界--11100111-10010101-10001100
可以看到用 UTF-8 編碼之後,英文字元佔用一個位元組,而漢字佔用了三個位元組,一共需要 11個位元組,而如果直接儲存 Unicode 碼則需要 14 個位元組。 UTF-8 編碼對於英文來說節省了很大空間,但是對於中文來說增加了空間。
上面提到 Unicode 是用兩個位元組表示字元,如果第一個位元組在前,就是"大端方式"(Big endian),第二個位元組在前就是"小端方式"(Little endian)。'世'字的 Unicode 碼是 4E16 ,一個位元組是 4E ,一個位元組是 16 , 儲存的時候如果 4E 在前就是大端儲存,如果是 16 在前就是小端儲存。
那麼計算機是怎麼知道一個檔案是採用哪種編碼方式呢?
Unicode 規範定義,每一個檔案的最前面分別加入一個表示編碼順序的字元,這個字元的名字叫做"零寬度非換行空格"(zero width no-break space),用 FEFF 表示。這正好是兩個位元組,而且 FF 比 FE 大 1 。
如果一個文字檔案的頭兩個位元組是 FE FF ,就表示該檔案採用大頭方式;如果頭兩個位元組是 FF FE ,就表示該檔案採用小頭方式。
UTF-8 編碼是基於 Unicode 字符集的一種編碼實現。現在幾乎所有的程式語言和作業系統都支援 Unicode 編碼,使用 Unicode 編碼之後,再也不會出現上文提到的一個漢字等於兩個英文字元的尷尬局面。
GBK , BIG5 等都屬於區域性編碼只能在固定範圍內使用,比如 GBK 只適合在簡體中文環境使用,雖然 GBK 相比於 UTF-8 更節省空間,但現在全世界都變成地球村了,所以還是建議大家都使用 UTF-8 編碼。
ANSI :在 window 下,如果我們用記事本開啟文件,經常會見到 ANSI 編碼方式,這是 Windows 預設的編碼方式。對於英文文件採用 ASCII 編碼,對於簡體中文文件採用 GB2312 編碼(只針對 Windows 簡體中文版,如果是繁體中文版會採用 Big5 碼)。
原文地址:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31559985/viewspace-2685543/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 為什麼用 Java:一個 Python 程式設計師告訴你JavaPython程式設計師
- 作為一個程式設計師,CPU的這些硬核知識你必須會!程式設計師
- 一個故事告訴你什麼才是好的程式設計師程式設計師
- 作為程式設計師,我意識到我有的一些毛病程式設計師
- 我來告訴你,一個草根程式設計師如何進入BAT程式設計師BAT
- 碼教授告訴你IT程式設計師如何找到高薪職業程式設計師高薪
- 為什麼每個程式設計師都應該學習程式碼編譯器知識程式設計師編譯
- 好程式設計師Web前端分享一些小知識!程式設計師Web前端
- 大牛告訴你,只有突破程式設計師思維,才不會淪為碼農!程式設計師
- 作為程式設計師應具備的基本知識 (轉)程式設計師
- Web設計師需要編碼知識嗎?Web
- 作為一個Java 程式設計師 你應該會什麼Java程式設計師
- 一圖告訴你 BAT 明星程式設計師是如何跳槽的BAT程式設計師
- 作為過來人,我想告訴準程式設計師的那些事程式設計師
- 程式設計師都應學習程式碼編譯器知識程式設計師編譯
- 每個程式設計師都需要知道一些遊戲網路知識程式設計師遊戲
- 作為一個程式設計師,你的進步完全取決於你自己程式設計師
- 作為一個程式設計師 你的進步完全取決於你自己程式設計師
- 一個故事告訴你,學習程式設計是否需要天賦?程式設計
- 如何“友好”地告訴經理:有一個好程式設計師是你的幸運?程式設計師
- 你是一個編寫可除錯程式碼的程式設計師嗎?除錯程式設計師
- 作為一個程式設計師的學習思考程式設計師
- 作為一名程式設計師 需要不斷豐富自己的知識庫程式設計師
- 作為一個程式設計師,數學對你到底有多重要程式設計師
- 為什麼你作為一個.NET的程式設計師工資那麼低?程式設計師
- 我來告訴你,草根程式設計師如何進入BAT程式設計師BAT
- 告訴你架構師與程式設計師的區別在哪裡架構程式設計師
- 好程式設計師告訴你Java架構師學習路線程式設計師Java架構
- 作為一個開發人員,你需要了解的一些HTTP基礎知識HTTP
- 作為一名程式設計師,你真的理解需求嗎?程式設計師
- 作為一個新手程式設計師該如何成長?程式設計師
- 作為一個菜鳥程式設計師跳槽可行嗎?程式設計師
- 作為一個程式設計師我最大的遺憾程式設計師
- 作為一個程式設計師,需要學習多少技能?程式設計師
- 讓老媽告訴你如何程式設計程式設計
- 作為一個Java程式設計師,這 8 個開源類庫你必須知道!Java程式設計師
- 邁進java初中級程式設計師分水嶺是否合格?十個題告訴你!Java程式設計師
- 5個理由告訴你,為什麼UX設計那麼貴UX