UTF8和GBK編碼互轉(zhuǎn)實(shí)現(xiàn)解析
基本知識(shí)
UTF8 本質(zhì)是 Unicode 標(biāo)準(zhǔn)的一種實(shí)現(xiàn)方式,UTF8 編碼和 Unicode 字符碼是有相互轉(zhuǎn)換的規(guī)則的。GBK 碼與 Unicode 字符碼是沒(méi)有設(shè)計(jì)有規(guī)律的對(duì)應(yīng)關(guān)系的,即沒(méi)有相互轉(zhuǎn)換的規(guī)則。所以想要實(shí)現(xiàn) UTF8 和 GBK 編碼互轉(zhuǎn)需要依靠查表法,即 UTF8 轉(zhuǎn) GBK 編碼需要先按規(guī)則轉(zhuǎn)換成 Unicode 字符碼,再通過(guò)查表獲取該 Unicode 字符碼對(duì)應(yīng)的 GBK 碼,同樣的 GBK 轉(zhuǎn) UTF8 編碼也需要先查表獲取對(duì)應(yīng)的 Unicode 字符碼,再按照規(guī)則轉(zhuǎn)換成 UTF8 編碼。
獲取 GBK 和 Unicode 的編碼對(duì)應(yīng)表
這里介紹兩個(gè)編碼對(duì)應(yīng)表,分別是 CP936 編碼表,和漢字 Unicode 編碼表,包含的漢字都是基本漢字,一共 20902 個(gè)。除去 ASCII 字符外,這些編碼中包括的漢字都是兩個(gè)字節(jié)的長(zhǎng)度。 其中 CP936 編碼表是按照遞增的 GBK 編碼值為索引的,對(duì)應(yīng)值是 Unicode 編碼,(由于 GBK 的編碼并不是連續(xù)的,所有索引之間往往有空缺),而漢字 Unicode 編碼表是以遞增的 Unicode 漢字字符碼為索引的,對(duì)應(yīng)值是 GBK 編碼(Unicode 編碼范圍 4E00-9FA5) 。
實(shí)現(xiàn)互轉(zhuǎn)
在獲取編碼表之后,想要實(shí)現(xiàn) GBK 和 Unicode 互轉(zhuǎn)的功能就沒(méi)有什么難度了,最簡(jiǎn)單的方法就是定義一個(gè)編碼數(shù)組包含 GBK 和 Unicode 的映射關(guān)系,然后對(duì)所需要轉(zhuǎn)換的編碼進(jìn)行查表,獲取對(duì)應(yīng)編碼再拼接成一個(gè)數(shù)據(jù)串就完成了。
采用 CP936 編碼表:
需要定義一個(gè) short 型二維數(shù)組存放 GBK 和 Unicode 的映射關(guān)系(因?yàn)?GBK 編碼值不是遞增的,中間有很多未使用的值),無(wú)論是 GBK 轉(zhuǎn) Unicode 還是 Unicode 轉(zhuǎn) GBK 使用時(shí)最長(zhǎng)需要遍歷整個(gè)數(shù)組。
采用漢字 Unicode 編碼表:
需要定義一個(gè) short 型一維數(shù)組,存放從 4E00-9FA5 直接的漢字字符,Unicode 的編碼字符減去 4E00 既是一維數(shù)組的索引。在 Unicode 轉(zhuǎn) GBK 時(shí)可以直接計(jì)算出對(duì)應(yīng) GBK 的索引值,直接獲取該編碼值即可。在 GBK 轉(zhuǎn) Unicode 的時(shí)候最長(zhǎng)需要遍歷整個(gè)數(shù)組。
明顯可以看出來(lái),使用漢字 Unicode 編碼表的時(shí)間復(fù)雜度和空間復(fù)雜度是低于使用 CP936 編碼表的,不做優(yōu)化的話,這里肯定選擇漢字 Unicode 編碼表。
優(yōu)化占用空間
缺點(diǎn):
上面雖然實(shí)現(xiàn)了 GBK 和 Unicode 的互相轉(zhuǎn)換,但是在程序里面定一個(gè) 20902 長(zhǎng)度的 short 數(shù)組還是太臃腫了,而且在某些情況嵌入式系統(tǒng)中是不允許定義這么多的。
優(yōu)化:
這里我們可以把編碼表改造成字庫(kù)文件。在帶操作系統(tǒng)的環(huán)境下以讀取文件的方式來(lái)讀取字符編碼。在嵌入式系統(tǒng)中沒(méi)有文件系統(tǒng)的環(huán)境下,我們可以把字庫(kù)文件燒入 Flash,以讀取 Flash 的方式來(lái)讀取字符編碼。
制作字庫(kù)文件:
漢字 Unicode 編碼表制作字庫(kù)文件并不復(fù)雜,新建一個(gè) .txt 文件(以 ANSI 格式打開(kāi)),將 Unicode 4E00-9FA5 對(duì)應(yīng)的 GBK 編碼依次復(fù)制到文件中保存,修改名字為 GBK.bin 就可以了。(這里 GBK.bin 是沒(méi)有文件頭和校驗(yàn)值的,直接按照索引讀取就行,需要注意的事這里不能有換行符)
優(yōu)化查找編碼速度
缺點(diǎn):
使用 GBK.bin 優(yōu)化了程序占用的空間,但是 GBK 轉(zhuǎn) Unicode 的時(shí)候最長(zhǎng)仍需要遍歷整個(gè)字庫(kù)文件,而且有一部分常用的字符是在 4E00-9FA5 后段部分的,這就導(dǎo)致了很多情況下查找效率的降低。
優(yōu)化:
漢字 Unicode 編碼表是根據(jù) Unicode 排序的,CP936 編碼表是根據(jù) GBK 排序的,我們可以將 CP936 編碼表也制作成字庫(kù) CP936.bin,在 GBK 轉(zhuǎn) Unicode 的時(shí)候使用字庫(kù) CP936.bin,在 Unicode 轉(zhuǎn) GBK 時(shí)使用 GBK.bin,這樣互轉(zhuǎn)都是按照編碼索引轉(zhuǎn)換成字庫(kù)索引直接讀取對(duì)應(yīng)字庫(kù),就省去了遍歷的過(guò)程。
制作字庫(kù)文件:
CP936 編碼表中的一部分 GBK Unicode 0x81FD 0x4FA1 0x81FE 0x4FA2 0x8240 0x4FA4 0x8241 0x4FAB
如上所示,GBK 的索引是不連續(xù)的,81FE 后面接的是 8240,實(shí)際上整個(gè) CP936 中類似于此的斷層大概有一百多處,每處缺少的數(shù)目是不一樣的,這里我們可以通過(guò)編寫(xiě)程序?qū)⑵溲a(bǔ)全索引,對(duì)于的 Unicode 的值設(shè)置成 0000,并寫(xiě)入 GBK.bin 文件(這里對(duì)于大的斷層我們進(jìn)過(guò)濾,并在后面的索引計(jì)算中進(jìn)行特殊處理,以免補(bǔ)出來(lái)的 bin 文件過(guò)大)。
優(yōu)化字串轉(zhuǎn)換速度
上面都是單個(gè)編碼去計(jì)算索引,讀取文件獲取編碼返回,在大量的字符串轉(zhuǎn)換的時(shí)候會(huì)有很多冗余的操作,我們可以進(jìn)行流程上的優(yōu)化,把所有需要獲取的字符編碼先全部轉(zhuǎn)換成索引,然后在去字庫(kù)中一次將所有需要的內(nèi)容都讀出來(lái)統(tǒng)一返回,這樣減少了流程上的調(diào)用。
UTF8 和 Unicode 的互轉(zhuǎn)
GBK 和 Unicode 的互轉(zhuǎn)已經(jīng)實(shí)現(xiàn)了,剩下的就是 UTF8 和 Unicode 的轉(zhuǎn)換,這部分就有固定的轉(zhuǎn)換規(guī)則如下:
UTF8 編碼規(guī)則:如果只有一個(gè)字節(jié)則其最高二進(jìn)制位為 0,如果是多字節(jié),其第一個(gè)字節(jié)從最高位開(kāi)始,連續(xù)的二進(jìn)制位值為 1,1 的個(gè)數(shù)決定了其編碼的字節(jié)數(shù),其余各字節(jié)均以 10 開(kāi)頭。
// Unicode6.1定義范圍:0~10 FFFF // 20 0000 ~ 3FF FFFF 和 400 0000 ~ 7FFF FFFF 屬于 UCS-4,UTF8 現(xiàn)在已經(jīng)棄用了這部分內(nèi)容 --------------------------------------------------------------------------------- n | Unicode (十六進(jìn)制) | UTF - 8 (二進(jìn)制) --+-----------------------+------------------------------------------------------ 1 | 0000 0000 - 0000 007F | 0xxxxxxx 2 | 0000 0080 - 0000 07FF | 110xxxxx 10xxxxxx 3 | 0000 0800 - 0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx 4 | 0001 0000 - 0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx --------------------------------------------------------------------------------- // 以下部分棄用 5 | 0020 0000 - 03FF FFFF | 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 6 | 0400 0000 - 7FFF FFFF | 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx ---------------------------------------------------------------------------------
以上就是UTF8和GBK編碼互轉(zhuǎn)實(shí)現(xiàn)解析的詳細(xì)內(nèi)容,更多關(guān)于UTF8 GBK編碼互轉(zhuǎn)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
OpenAI?函數(shù)調(diào)用示例及功能入門(mén)教程
這篇文章主要為大家介紹了OpenAI?函數(shù)調(diào)用示例及功能入門(mén)教程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06程序員開(kāi)發(fā)項(xiàng)目是選擇效率還是質(zhì)量呢?
這篇文章主要介紹了程序員開(kāi)發(fā)項(xiàng)目是選擇效率還是質(zhì)量呢?本文對(duì)這個(gè)每個(gè)程序員都會(huì)遇到的一個(gè)問(wèn)題做了講解,需要的朋友可以參考下2014-07-07git-github 子模塊倉(cāng)庫(kù)更新(git submodule)及git中submodule子模塊
這篇文章主要介紹了git-github 子模塊倉(cāng)庫(kù)更新(git submodule)/git中submodule子模塊的添加、使用和刪除,使用子模塊后,不必負(fù)責(zé)子模塊的維護(hù),只需要在必要的時(shí)候同步更新子模塊即可,需要的朋友可以參考下2023-03-03vscode配置遠(yuǎn)程開(kāi)發(fā)與免密登錄的技巧
這篇文章主要介紹了vscode配置遠(yuǎn)程開(kāi)發(fā)與免密登錄的技巧,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04Web開(kāi)發(fā)/設(shè)計(jì)人員應(yīng)當(dāng)知道的15個(gè)網(wǎng)站
建個(gè)好網(wǎng)站絕非易事,工欲善其事必先利其器。本文編譯了15個(gè)極其有用的網(wǎng)站,任何一位網(wǎng)站開(kāi)發(fā)者或設(shè)計(jì)人員都應(yīng)該收藏起來(lái)2011-05-05FedAvg聯(lián)邦學(xué)習(xí)FedProx異質(zhì)網(wǎng)絡(luò)優(yōu)化實(shí)驗(yàn)總結(jié)
這篇文章主要為大家介紹了FedAvg聯(lián)邦學(xué)習(xí)FedProx異質(zhì)網(wǎng)絡(luò)優(yōu)化的實(shí)驗(yàn)總結(jié),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05