自從上次發佈「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-hk/n/273794.html
微信掃一掃
支付寶掃一掃