跟濤哥一起學嵌入式 26:深入淺出計算機編碼、亂碼問題

很多新手在編寫程序、使用軟件打開文檔或者瀏覽網頁時,經常遇到亂碼顯示、全角半角的問題。

 

v2-baa4c2b19f9654d014a7867a9a9a7d73_b.jpg

網上也有很多解決的方法,大部分都是跟編碼有關:比如Unicode、UTF-8、ASCII碼、GB2312...,令人眼花繚亂,今天就給大家理一理它們之間的關係。

 

v2-71451076fe083c53f0b2785288fc5dff_b.jpg

計算機只認識0和1這兩個數字,我們輸入的程序代碼、文字都要經過編碼,然後才能被計算機識別、解析和存儲。早期的計算機環境是主要是英文,我們對構成英文的這些基本字母:拉丁字母編碼就可以了,比如ASCII碼。

ASCII碼使用一個8位的單字節數據來編碼電腦中常用的各種字符,如

  • 拉丁字母:A、B、...、Z,a、b、...、z
  • 數字:1、2、3、4、5、6、7、8、9
  • 標點符號:逗號、句號、省略號
  • 控制字符:回車符、換行符、空格符、製表符等

 

v2-77f6833ccc840bfb82d3c8546b5858ed_b.jpg

ASCII碼使用單字節的 bit0 ~ bit7 ,可以表示128個英文常用的拉丁字母和各種控制字符,這在英文環境下足夠用了,隨着計算機的普及,每個國家或地區都有自己個文字,這就給計算機的顯示的麻煩,計算機中沒有其他文字的編碼,遇到這些文字,肯定沒辦法解析和顯示了,顯示的可能是一片亂碼。

世界三大字母

爲了顯示各國語言文字,我們需要對世界上各種語言做些分類。世界上的語言很多,主要可分爲兩類:象形型文字和字母型文字。象形型文字如漢字,除此之外,絕大部分語言文字都是字母型文字,基本上都是基於以下三大字母表去構建的。

  • 拉丁字母:英語、法語、德語、意大利語、荷蘭語、西班牙語、漢語拼音
  • 阿拉伯字母:阿拉伯語、波斯語、維吾爾文
  • 斯拉夫字母:俄語、烏克蘭語、波蘭語、白俄羅斯語、吉爾吉斯、烏茲別克、新蒙古語

 

v2-6f59bb4f88756e1d34eeb69e1b27e5a2_b.jpg
阿拉伯字母

 

v2-bbe4f821486e422c80513f0a6600c3f6_b.jpg

斯拉夫字母

古希臘作爲歐洲文明的起源,拉丁字母和斯拉夫字母都起源於希臘字母。希臘字母廣泛用於數學、物理、生物、化學、天文等學科,如大家熟悉的α(Alpha)、β(Beta)、Ω(Omega)、Δ(delta)。後期經東正傳教士傳播到斯拉夫民族區並加以改造,就變成了斯拉夫字母。羅馬人引進希臘字母后,稍加改變就成了拉丁字母。拉丁字母是世界上最流行,英語、法語、德語、西班牙語,甚至我們使用的漢語拼音都是使用拉丁字母,再加上早期的計算機主要在歐美,所以早期的計算機字符編碼使用拉丁字母也就不奇怪了。

由於希臘字母在很多科研領域中的廣泛應用,爲了顯示這些希臘字符,ASCII碼進行了擴展了字符集,由原來的128個擴展到了256個:增加了希臘字母、特殊的拉丁符號以及一些表格符號、計算符號等。

ASCII編碼簡單點理解,其實就是一個字符集,每個字符通過編碼,可以很方便地在計算機上被識別和存儲。ASCII碼的缺陷是使用單字節存儲,最多也就知道編碼256個字符,容量有限,尤其是各國都有自己的語言文字,比如中文,常用的就有近3000個漢字。再使用單字節編碼存儲肯定不行,需要擴充這些字符集。

GB2312編碼

以微軟操作系統爲例,基本上世界各國都在使用它,都要顯示自己的文字,比如我們要使用中文版的操作系統,要顯示中文,怎麼辦?微軟採用的方案是:各國採用各自的編碼方案。以中文爲例,我們有上萬的漢字需要編碼、存儲,採用的是GB2312編碼:0~127單字節編碼表示原來的拉丁字母A~Z、a~z等,從127往後,每兩個字節表示一個漢字。高低字節的編碼方式可以編碼6000多個常用漢字,除此之外,還把數學符號、羅馬希臘字母、阿拉伯字母、俄文字母、日文的平假名、片假名都編進去了,就連ASCII表中原有的數字、字母、標點符號都使用雙字節重新編碼,這就是我們平常所說的全角字符,127號以下的那些單字節字符叫半角字符。GB2312編碼可以看作是對ASCII的擴展。

GBK標準

中文除了簡體,還有繁體字,也需要對這些繁體字進行編碼。早期臺灣地區使用BIG5編碼對繁體字進行編碼,也是採用雙字節存儲。隨着電腦的普及,國內少數民族也要使用電腦,各個民族也有自己的語言系統。爲此,GB2312字符集不斷擴充,不斷加入新的字符編碼,於是就產生了GDB編碼,並逐漸成爲中文編碼的標準。根據這個標準,可以將不同漢字進行編碼構成字庫,計算機想顯示漢字,根據編碼到字庫去查就可以了。早期的計算機內存、存儲資源有限,將字庫固化到硬件ROM中,插到計算機上就可以了,這就是漢卡。《征途》老闆史玉柱,當年就是靠這個漢卡起家的,賺得第一桶金,登上人生巔峯。現在的計算機一般不適用漢卡了,改用軟件字庫代替,直接存放到硬盤就可以了。

Unicode編碼

各國都使用自己的編碼方案,搞出一套自己的編碼標準。用戶在安裝好Windows系統後,設置成本國語言就可以正常使用Windows了,可以正常顯示本國的文字。在Windows系統中,簡體操作系統使用的GBK,繁體操作系統使用的是BIG5,各個地區的本地編碼方案作爲不同語言版本的Windows的ANSI編碼標準。但這種編碼方案很容易出問題,隨着互聯網興起,各國網民使用瀏覽器瀏覽網頁時,瀏覽他國的網頁時,如果本地字庫沒有編碼這些網頁的外語字符就很容易亂碼。爲了解決這個問題,ISO國際標準化組織廢除了所有的地區性編碼方案,重新搞了一套包括地球上所有語言、字母、字符的編碼:Universal Multiple-Octet Coded Character Set,簡稱Unicode編碼,又叫國際碼。

Unicode編碼使用雙字節來編碼字符,一共可以編碼65536個字符,這足以容納地球上所有的語言文字和字符了,而且可以把所有的語言都編進去,全世界通用,多好!

UTF-8編碼

Unicode編碼作爲國際碼,解決了各國編碼衝突問題,但是缺陷還是有的:浪費存儲空間。比如原來的英文字符編碼,單字節就可以了,現在是雙字節,編碼後的文件體積足足增大了一倍,不利於網絡傳輸。爲此,基於Unicode編碼標準,UTF-8編碼在存儲上做了改進:採用變長字節(1~6個字節)來存儲Unicode字符,原來的ASCII碼採用單字節存儲;希臘字母、斯拉夫字母採用2字節存儲;漢字採用3字節存儲。Linux環境下一般採用UTF-8編碼存儲文件,採用UTF-8編碼存儲的文件一般在文件頭會有3個字節的UTF-8編碼標記。而在Windows下,一般使用UTF-16編碼來存儲Unicode字符,文件頭有2個字節的UTF-16編碼標記。

文件編碼實驗

我們在Windows下創建一個文本文件,輸入4個漢字:宅學部落。保存文件分別保存爲不同的編碼格式:ANSI、Unicode、UTF-8,查看文件大小,分別爲8字節、10字節、15字節。如果輸入英文字符:wang,再分別保存並查看各個文件大小,大小分別爲:4字節、10字節、7字節。

 

v2-651deb8d3bb8a711032d4dd750546c54_b.jpg

通過實驗我們可以看到,使用UTF-8編碼漢字,每個漢字3個字節,生成的文件體積比較大。因此很多中文操作系統下,經常還是有很多人使用GBK標準編碼的。爲了區分各種編碼,一般在文件頭會有幾個字節說明該文件的編碼方式,比如UTF-8文件編碼存儲的文件頭部會有3個隱藏字節(0xEF 0xBB 0xBF)標記UTF-8編碼,UTF-16文件頭有2個字節(FE FF或FF FE)用來標記UTF-16編碼方式,這種標記數據一般稱爲BOM頭。

在Windows下使用記事本,如果採用Unicode存儲,默認是自動給文件添加BOM頭的。而在Linux下的文本文件雖然默認使用UTF-8標準,但是編碼生成的文件一般是不帶BOM頭的,這也是很多新手在Windows下用記事本編寫程序或者腳本,然後拷貝到Linux系統中運行,發現總是錯誤的原因。現在高級點的文本編輯器,如sublime、UltraEdit、notepad++等,都支持“UTF-8 無BOM”保存方式,編輯保存的文件更適合跨平臺保存和運行。

 

小結

以上給大家分享了不同語言文字、各種程序源文件、各種文本文檔在計算機中如何編碼和保存的小知識。不同的操作系統、不同的軟件在存儲字符到文本文件時,不僅編碼方式不同,而且還會有BOM頭的差異。理解了這些基本原理和細節後,大家在以後的編程中再遇到類似的問題,就迎刃而解了。

嵌入式技術QQ羣:宅學部落

微信公衆號:宅學部落

發佈了92 篇原創文章 · 獲贊 38 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章