講一個字符編碼的故事,你仔細聽

各位:請自帶飲料自帶茶,自帶板凳自帶糖,坐好,憋說話,我講個故事,你仔細聽,講完留作業!

很久以前,有一羣美國人,他們發明了計算機之後,想用一個字節也就是八位二進制數來表示一切可以形象化的文字。比如我想保存字母a,我就把01100001傳給計算機幫我保存起來,這個過程叫編碼(encode);反之,當計算機讀取數據遇到01100001時,計算機就顯示字母a,這個過程呢,叫做解碼(decode)。後來這羣人無恥的制定了一套標準,試圖統治世界,這就是ASCII碼。他們掰着手指加上能想到的控制符號,也就編到了127號,這羣美國佬發現自己真是太牛逼了,他們天真的認爲我們把128 - 255的編碼位置留出來,我能encode一個宇宙。

後來,歐洲人也用計算機了,歐洲人發現美國佬真的是仗義,還給他們留着一半的編碼空間,於是貪婪的歐洲佬把128-255的編碼位置全都佔了,這也就是我們常說的不是國際標準的擴展ASCII碼錶的其中一種。

再後來,計算機傳到了我們偉大的祖國,當時的計算機專家掐指一算,大約最起碼我們要6000多個編碼位置就夠啦,勤勞聰慧的中國人民就可以用上可以顯示漢字的電腦啦,後來看了ASCII碼錶之後有一位專家提出,哎呀,256個,不如還是我們一起去學英語呀。後來這名專家被打了一頓之後,去了教育局。

其他的專家一看,我擦,有些字符集127號之後都是啥鬼畫符,於是,我們偉大的前輩毫不猶豫的拋棄了那羣貪婪的人添加的字符集擴展部分,並大膽提出:127號之前的兼容ACSII碼錶,我們把大於127的兩個字節連在一起,表示一個漢字,第一個字節爲高位字節(也叫區字節),第二個字節爲低位字節(也叫位字節),高位字節使用了0xA1-0xF7低位字節使用了0xA1-0xFE。這樣我們大約搞出了6763個漢字以及非漢字圖形符號682個,並且我們把ACSII本身存在的標點·數字·字母重新以兩個字節的編碼方式重新搞了一個放到裏面,這就是我們常說的全角字符,原ACSII127號以下的也就是我們說的半角字符啦。前輩們給它起了一個名字:信息交換用漢字編碼字符集,也就是我們常說的GB2312

好景不長,五千年的風和雨啊,不是鬧着玩的,你爸去給你落戶的時候發現計算機打不出這個字。面對這種情況,我們乾脆不再要求位字節要大於127,只要區字節大於127就可以。它兼容GB2312,同時收錄內容也提升至23940個碼位,其中有漢字21003這也就是漢字內碼擴展規範,也就是我們常說的GBK

經過上面過程的演變,我國的人民終於可以更方便的使用計算機了。老一輩程序員也非常高興,就這樣,這種雙字節字符集在坊間廣泛流傳了起來,相信一定聽過一句名言:一個漢字是兩個英文字符

就這樣,在我們沾沾自喜的時候,世界各地計算機開發者以及使用者也如雨後春筍,字符集以及編碼規範也是百家爭鳴,互不兼容,亂碼遍地,就在大家苦惱不已但又誰都不服誰的時候,有兩撥人不僅意識到這個問題的嚴重性,而且着手創建一個通用字符集,其中一撥人就是國際標準化組織ISO),他們制定了UCS字符集(Universal Character Set),另一撥人則是美國多語言服務提供商的財團發起的Unicode項目,他們都用四位十六進制數,也就是兩個字節來表示一個字符,也就是65535個碼位(後續有UCS-4,也就是四個字節表示一個字符,共21億個字符,應該夠用了哦)。後來,兩撥人意識到世界上不需要兩個統一的通用字符集,所以他們合作制定了一個字符表,也就是我們目前所見最多,打破你一個漢字是兩個英文字符的觀點的Unicode/UCS(多少次老師殷切的叮嚀變成你被其他程序員恥笑的理由)。

在這裏要說一下,Unicode/UCS只是字符集,每一個字符雖然對應一個碼位,但是用什麼字節以及多少個字節來表示這個字符,是由字符編碼決定的,上面我們提到的ASCIIGB2312GBK等地區編碼標準制定時,一般字符集和字符編碼時同時制定的,也就是說ASCII等不僅僅是字符集,更是一種字符編碼格式。

Unicode只是一個字符集,它的字符編碼有UTF-8,UTF-16,UTF-32。隨着計算機網絡的興起,UTF-8編碼越來越體現出他的優勢:不僅可以向前兼容ASCII碼,是變長的編碼,並且由於編碼沒有狀態,所以很容易重新同步,在傳輸過程中丟失了一些字節後,具有魯棒性。
我們來看一下UTF-8對Unicode進行編碼的方式如下:

比如,“漢”字的Unicode編碼是U+6C49。0x6C49在0x0800-0xFFFF之間,使用用3字節模板了:1110xxxx 10xxxxxx 10xxxxxx。將0x6C49寫成二進制是:0110 1100 0100 1001, 用這個比特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。

聰明的你肯定意識到我看到的Unicode碼不是這樣的啊,我看到的都是\u****這樣的,那就再提一嘴轉譯序列,在C語言中,\u6C49代表字符名稱爲U+6C49的Unicode碼。
你肯定還去去試我例子中的UTF-8編碼後的字節傳能不能轉化成漢字,於是你打開網頁,搜索UTF-8轉化,於是你快樂的把E6 B1 89輸入進去:得到的結果還是E6 B1 89,你肯定有點懵逼,以爲我在忽悠你,於是你打算取關我,於是你輸入”漢“字,於是你得到的結果爲&#x6C49,先彆着急取消關注我,聽我解釋啊:
其實,和上面我們提到的爲什麼\u****並不是純正的Unicode碼位對應的十六進制數差不多,我們看到的東西,都是經過IDE或者Html等搞過的,所以它們會通過一些特殊的方法去簡化或者說標誌一種編碼方式。
在XML及其子集HTML採用UTF-8作爲標準字集,理論上我們可以在各種支持XML標準的瀏覽器上顯示任何地區文字的網頁,只要電腦本身安裝有合適的字體即可。可以利用&#nnn;的格式顯示特定的字符。nnn代表該字符的十進制 Unicode 代碼。如果採用十六進制代碼,在編碼之前加上x字符即可。但部分舊版本的瀏覽器可能無法識別十六進制代碼。是不是和你剛纔的東西吻合了呢?

剛纔取消關注的那個哥們兒,關注回來唄!
最後,我們來變個魔術:

在 windows 電腦上新建一個記事本,輸入"聯通"兩個字之後,保存,關閉,然後再次打開,試一下,就是見證奇蹟的時刻,不要懵逼,放開你的想象力,你知道爲什麼嗎?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章