先扯一會男人胯下那兩個東西
今天,朋友找我問一個在 WebBrowser 裡加載 HTML 頁面亂碼的問題,幫她處理過以後,她嘟囔了一句 “編碼什麼的我完全不懂啊”……
這裡的她,已經有三年的工作經驗,大大小小的項目也參與過幾個,可是對于這個問題,還是似懂非懂。
不隻是她,其實還有好多工作多年的朋友對這個問題還不甚了解,因為工作原因,隻知道出現亂碼以後改改配置檔案,開發工具裡設定一下就能解決,深層次的原因,還是不很了解,或者是沒必要了解,也不想去了解。
前段時間就有一個朋友,有點裝逼的朋友,接觸程式設計十來年了,工作也有七八年了,現在在一個在當地小有一些名氣的軟體公司任技術經理。我們合作了一個小項目,他用 Java 負責雲端,我用 C# 做用戶端。我設計了一個 Lincenses 生成、校驗的算法,主要是拿硬體ID、裝置編号、授權日期這些參數生成一個16位的注冊碼,使離線版的用戶端能夠被系統管控。為了避免輕易被猜解,我加了随機混淆的機制。當我把這個 Licenses 算法的 Java 版代碼給他的時候,他死活不相信是我寫的,甚至至今,提起那個項目,他還說我“網上找的算法”……~~~無語~~~多大個事兒啊,也就把源資料的編碼轉來轉去拼拼湊湊處理一下而已,但是,他不會~~~
也确實,大多數編碼的問題開發環境都替我們解決了,隻在項目布署的時候,或者多方通信的時候,才會考慮編碼問題。是以,很多人對“編碼”這個東西并沒有多深刻的了解。
啥是編碼?
要說起“編碼”這玩意兒,事實上一直伴随我們左右,甚至可以說是一個“最熟悉的陌生人”,比如:“郵政編碼”。
“編碼”的概念,在百科上是這樣解釋的:“編碼是資訊從一種形式或格式轉換為另一種形式的過程也稱為計算機程式設計語言的代碼簡稱編碼。用預先規定的方法将文字、數字或其它對象編成數位,或将資訊、資料轉換成規定的電脈沖信号。編碼在電子計算機、電視、遙控和通訊等方面廣泛使用。編碼是資訊從一種形式或格式轉換為另一種形式的過程。解碼,是編碼的逆過程。”
簡單來講,編碼是資訊從一種形式或格式轉換為另一種形式的過程。
概念比較抽象,我們還拿郵政編碼來舉例。
郵局,那個神奇的、無孔不入、無所不達又無比大爺的神奇機構,他們為了提高郵件的投遞效率,為了快速的區分像 “中華人民共和國新疆維吾爾自治區 伊犁哈薩克自治州 察布查爾錫伯族自治縣 奧依亞依拉克鄉 奧依亞依拉克村村民委員會 古且末國曆史文化遺址 申報聯合國教育科學文化組織 世界非物質文化遺産工作上司小組辦公室” 這種奇葩的位址,他們把全中國每一個區域都編一個6位數字的編碼。無論你位址再長,那怕長的能寫一篇論文,也隻用6位數字代替,這樣經驗豐富的分撿人員瞄一眼就能知道這個郵件是寄往哪裡的。這個6位數字編碼,就是郵政編碼。也就是說,全國的每一個地區,都可以用一個6位數字的編碼代替,這個6位數字,就是這個地區的“編碼”。
編碼,做為名詞時,可以了解為一一對應的一種資訊轉換規則;做為動詞時,可以了解為資訊轉換的過程。
除了郵政編碼,我們身邊還有很多各種各樣的編碼,比如:“身份證編碼”,“畢業證編碼”等等。
實際上,上面扯的那麼多,都是蛋。扯出去了,再扯回來。
碼農眼中的編碼
在計算機世界裡,所有資料最原子的機關是位,英文叫 bit。每一個 bit 可選值有 1 或 0 兩個,可以了解成 True 或 False、有或無。這是二進制計算機系統的根本。計算機無論通信,還是存儲,都是以二進制的方式表達資訊。
老子說:太極生兩儀,兩儀生四象,四象生八卦,再生六十四卦,再生生萬物,一直生,這個世界就出來了。。。
在計算機世界裡,bit 生兩儀,兩儀生 256 卦,再生生萬物,一直生,就有了今天這麼豐富多彩的計算機世界。
bit 如果隻有一個,屁用都木有。幸運的是,bit 可以有很多很多很多很多個,多的你數不過來。
1 個 bit,隻能表示0 1、True False、有 無,可以表示一下下班了沒?餓了沒?困了沒?死了沒?沒啥大用。
2 個 bit 合在一起,就可以有4個組合:00、01、10、11。多少有點用處了:假設一個小組有4個人,00表示張三,01表示李四,10表示王五,11表示趙六。這樣兩個bit的空間就可以表達一個人了。
3 個 bit 合在一起,就可以有 8 種組合。當然表示的可能性更大。
4 個 bit,就可以有16種組合。
。。。。。
8 個 bit 就可以有 256 種組合。可以表示 128 對情侶(256個),當然也可以表示 256 條單身狗。當然也可以表示100對情侶外加56個單身狗。
反正是随着 bit 的數量累加,計算機可以表示的資訊越多,越豐富。
不過,純粹的 bit 堆疊确實能表示很多種資訊,但是,這些資訊使用起來不友善。抽象的一堆編号,很難了解其中的意義。
于是,許多年前,美國那堆磚家立志要解決這個問題。他們摳着腳指頭算了算,英文字母大小寫區分後有 52 個,再加 10 個數字還有标點符号,再加一些數學運算符,再扒開腦洞,使勁的造,拼湊夠了128個符号。128個符号才占7位啊,7位沒8位好聽,就再補一位吧。這樣 8 個 bit 的值就能表示美國人使用的一個符号或字母,或者統稱為字(位元組 byte)。這樣如果有16個bit的話,就可以表示兩個字,幾百個 bit 就能表示人能了解的一句話。(這一段是扯蛋話,不是正史)
這真是個好主意!
于是,一幫磚家開了個會,确定了這種分組方式。然後對這些字母和符号按他們自己的喜好排排序,确定了下來,就行成了今天我們看到的 ASCII 編碼表。如下圖:

于是乎,無論是什麼形式的一堆二進制資料,統統按照 8 個一組的方式進行截取,然後分别到 ASCII 表中找出對應的字元,就可以拼成一句美國人能了解的話。
說實話,這确實是一個很屌的發明。
再扯蛋一會兒
今天看了一個碼農發春的段子,與今天的主題相關,大概内容如下:
做為曾經的單身狗,看到最後美好的結局本來挺欣慰的。但是當發現這條狗給一個藝術系的妹子發 ASCII 碼的時候,不禁為妹子深(sao)沉(qing)的愛感到遺憾。這種作死狗就應該一輩子保持純潔的童子身。
不過,扯回今天的話題:這個妹子熬了半夜,做的工作就是編碼——将一組資料,編碼成目标資訊。
不過再說一句:這故事也太扯蛋了。
強行扯回主題
ASCII 碼是美國标準資訊交換碼,隻是一些拉丁字元及符号。它有一個非常缺心眼的地方:它隻能表示256個符号。而人世間,符号何止幾百個。
拿中文來說,有簡體繁體之分,甚至一個字多種寫法,加上各種生僻字,僅僅一個漢字就得好幾萬字元。ASCII 碼遠遠不夠用。
為了解決這個問題,有志之士們想了一個解決方案:一個8位不夠,可以用兩個 8 位甚至三個 8 位來表示一個字元,2 個 8 位的資料能表示 65536 個資料,3 個 8 位的資料能表示上千萬的資料。。
不過,悲催的是:因為世界文化的多樣性,好多人都開始使勁研究這些字元,每一幫人都覺得自己搞的很NB,然後釋出一個标準。每一套編碼都有自己的方式,而且互不相容。僅僅常用的中文編碼方式就有 Unicode、UTF-8、GB2312、GBK等。
這樣的結局就是:非常容易出現亂碼。比如一個漢字“中”,在編碼 A 裡,實際對應的值是1234;可是到編碼 B 裡,對應的值就是15352。
這 TM 就很尴尬了,當我儲存一個“中”字的時候,我用的是 A 編碼,這時候,磁盤上存的值是1234,然後下次取的時候忘了我用的是什麼編碼,就随便用 B 編碼去解悉,而在 B 編碼裡,1234可能根本就沒定義,或者定義的是一個别的字元。這樣拿 1234 用 B 編碼解悉完,看到的人就懵逼了。這就是我們常講的“亂碼”。
為了避免亂碼,就需要對資料進行轉碼。轉碼就是拿着 1234 強行使用 A 編碼解悉,這樣就能得到我想要的“中”字。
最後:
其實,我們的計算機處理的都是二進制數值,所有的我們看到的文字,圖像,視訊,都是要經過轉化才能展示給我們看的。編碼是對這些資料的不同處理規則,規則比對了,資訊就準确,規則不比對,資訊就沒辦法還原。其實資料還是那些資料,資料沒有對錯。