自從上次發布“Framebuffer應用編程”視頻後,
我們花了10多天調試STM32MP157板子,4.19內核、5.4內核全部調試通過!
在調試過程中,編寫了不少文檔,到時整理後再發布給大家,也許可以錄一個項目:
怎麼把廠家SDK移植到到自己的板子?
這是以後的事了,
從今天開始,韋老師又繼續錄製、發布視頻了。
今天發布文章:字符的編碼方式,視頻同步錄製中。
6.1 字符的編碼方式
6.1.1 編碼與字體
在計算機上,我們看到的字符“A”可能長這樣:

也可能長這樣:

對於同一個TXT文件中的內容,你在Notepad上選擇不同字體時,字符顯示的形狀不一樣。
所以TXT文件中保存的是字符的核心:它的編碼值。而Notepad上顯示時,這些字符對應什麼樣的形狀態,這是由字符文件決定的。編碼值,字體是兩個不一樣的東西,比如A的編碼值是0x41,但是在屏幕上顯示出來時可以使用不同的形狀。
什麼叫編碼?就是一個字符用什麼數字來表示。在計算機里一切都是用數字來表示,比如字符A,用0x01還是0x02來表示它?我們使用0x41來表示它。當你去打開一個TXT文件時,發現裡面含有數值0x41,你就知道了:哦,這裡有一個字符A。
一個字符用哪個數字來表示?有很多標準,舉例講解。
1. ASCII
是“American Standard Code for Information Interchange”的縮寫,美國信息交換標準代碼。
電腦畢竟是西方人發明的,他們常用字母就26個,區分大小寫、加上標點符號也沒超過127個,每個字符用一個字節來表示就足夠了。一個字節的7位就可以表示128個數值,在ASCII碼中最高位永遠是0。
字符和數值的對應關係可以參考:https://baike.baidu.com/item/ASCII
下面摘錄部分給大家一個印象:

2. ANSI
強烈建議閱讀:https://www.cnblogs.com/malecrab/p/5300486.html
使用記事本保存文件時,可以選擇“ANSI”編碼,卻沒有“ASCII”,如下圖所示。怎麼回事?

ASNI是ASCII的擴展,向下包含ASCII。對於ASCII字符仍以一個字節來表示,對於非ASCII字符則使用2字節來表示。並沒有固定的ASNI編碼,它跟“本地化”(locale)密切相關。比如在中國大陸地區,ANSI的默認編碼是GB2312;在港澳台地區默認編碼是BIG5。以數值“0xd0d6”為例,對於GB2312編碼它表示“中”;對於BIG5編碼它表示“笢”。所以對於ANSI編碼的TXT文件,如果你打開它發現亂碼,那麼還得再次細分它的具體編碼。
比如對於一個TXT文件,裡面的數值如下:

使用Notepad打開後,選擇不同的編碼(或稱為字符集),有不一樣的顯示,如下:

這僅僅是在中國地區就出現這些不兼容的問題。對於不同國家,它們默認的ANSI編碼各不相同,所以同一個TXT文件在不同國家就很有可能出現亂碼。
根本的原理在於沒有“統一的編碼”,那解決方法自然就是使用“統一的編碼”:UNICODE。
3. UNICODE
在ANSI標準中,很多種文字都有自己的編碼標準,漢字簡體字有GB2312、繁體字有BIG5,這難免同一個數值對應不同字符。比如數值“0xd0d6”,對於GB2312編碼它表示“中”;對於BIG5編碼它表示“笢”。這造成了使用ANSI編碼保存的文件,不適合跨地區交流。
UNICODE編碼就是解決這類問題:對於地球上任意一個字符,都給它一個唯一的數值。
UNICODE仍然向下兼容ASCII,但是對於其他字符會有對應的數值,比如對於“中”、“笢”,它們的數值分別是:0x4e2d、0x7b22
UNICODE中的數值範圍是0x0000至0x10FFFF,有1,114,111即100多萬個數值,可以表示100多萬個字符,足夠地球人使用了。

6.1.2 編碼實現
所謂編碼實現,就是對於一個數值,怎麼表示它。這很奇怪,數值還能怎麼表示?比如“中”的UNICODE值是0x4e2d,在TXT文件中怎麼表示0x4e2d?直接寫入0x4e2d?不行!
比如在TXT文件中寫入2字節數據“0x2d 0x4e”,它可以用來表示“中”字嗎?不能!它們對應ASCII字符“-N”。
問題的關鍵在於:怎麼斷字。在TXT文件中,2字節數據“0x2d 0x4e”是作為一個整體看待,還是拆成2部分看待?
所以,需要用一定的技巧來表示數值,這就對應不同的編碼實現。
現在我們知道:
1. ASCII編碼中使用一個字節來表示一個字符,只用到其中的7位,最高位恆為0;
2. ANSI編碼中,對於ASCII字符仍使用一個字節來表示(BIT7是0),對於非ASCII字符一般使用2個字節來表示,非ASCII字符的數值BIT7都是1。
3. UNICODE:這就有點複雜了,下面一一講解。
先用記事本新建3個文件:utf-16_le.txt、utf-16_be.txt、utf-8.txt、bom_utf-8.txt,裡面的內容都是“ab中”,保存時編碼分別選擇“UTF-16 LE”、“UTF-16 BE”、“UTF-8”、“帶有BOM的UTF-8”,下圖是其中一個例子:

怎麼表示一個UNICODE數值?
1. 使用3個字節表示一個UNICODE
不,太浪費。
UNICODE的最大值是0x10FFFF,那使用3個字節來表示一個UNICODE數值?這當然是很省事的方法,但是會造成浪費,比如字符A的UNICOCDE值是0x41,難道也用“0x41 0x00 0x00”這3個字節來表示?
2. UCS-2 Little endian/UTF-16 LE
每個UNICODE只用3字節來表示有點浪費,那隻用2字節呢?它可以表示2^16=65536個字符,全世界常用的字符都可以表示了。
Little endian表示小字節序,數值中權重低的字節放在前面,比如字符“ab中”在TXT文件中的數值如下,其中的“a”使用“0x61 0x00”兩字節表示;“b”使用“0x62 0x00”兩字節表示;“中”使用“0x4e 0x2d”兩字節表示。文件開頭的“0xff 0xfe”表示“UTF-16 LE”。

3. UCS-2 Big endian/UTF-16 BE
Big endian表示小字節序,數值中權重低的字節放在後面,比如字符“ab中”在TXT文件中的數值如下,其中的“a”使用“0x00 0x61”兩字節表示;“b”使用“0x00 0x62”兩字節表示;“中”使用“0x2d 0x4e”兩字節表示。文件開頭的“0xfe 0xff”表示“UTF-16 BE”。

4. UTF8
在上面2種方法中,每一個UNICODE使用2字節來表示,這有3個缺點:表示的字符數量有限、對於ASCII字符有空間浪費、如果文件中有某個字節丟失,這會使得後面所有字符都因為錯位而無法顯示。
使用UTF8可以解決上述所有問題。UTF8是變長的編碼方法,有2種UTF8格式的文件:帶有頭部、不帶頭部。先舉例,看下圖:

對於其中的ASCII字符,在UTF8文件中直接用其ASCII碼來表示,比如上圖中的0x61表示字符a、0x62表示字符b。上圖中的3個字節“0xe4 0xb8 0xad”表示的數值是0x4e2d,對應“中”的UNICODE碼。
對於非ASCII字符,使用變長的編碼:每一個字節的高位都自帶長度信息。請看下圖:

上圖中,0xe4的二進制是“11100100”,高位有3個1,表示從當前字節起有3字節參與表示UNICODE;
0xb8的二進制是“10111000”,高位有1個1,表示從當前字節起有1字節參與表示UNICODE;
0xad的二進制是“10101101”,高位有1個1,表示從當前字節起有1字節參與表示UNICODE;
除去高位的“1110”、“10”、“10”後,剩下的二進制數組合起來得到“01001110001101”,它就是0x4e2d,即“中”的UNICODE值。
使用UTF8編碼時,即使TXT文件中丟失了某些數據,也只會影響到當前字符的顯示,後面的字符不受影響。

原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/273794.html
微信掃一掃
支付寶掃一掃