• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆 - 17  文章 - 48  trackbacks - 0
            <2012年12月>
            2526272829301
            2345678
            9101112131415
            16171819202122
            23242526272829
            303112345

            常用鏈接

            留言簿(3)

            隨筆檔案

            搜索

            •  

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            這篇文章是我兩年多前寫(xiě)給同事看的,當(dāng)時(shí)不少同事對(duì)編碼了解甚少,直到現(xiàn)在發(fā)現(xiàn)還是很多人對(duì)編碼了解甚少,所以我就把這篇文章發(fā)出來(lái)讓大家參考一下,希望對(duì)一些人有幫助,不過(guò)這篇文章是當(dāng)時(shí)花了3個(gè)小時(shí)左右寫(xiě)的,錯(cuò)誤在所難免。

            字符編碼歷史

            計(jì)算機(jī),發(fā)明在20世紀(jì)中期西方國(guó)家。計(jì)算機(jī)內(nèi)部使用二進(jìn)制作為表示任何東西的基礎(chǔ),為了能夠在計(jì)算機(jī)中使用整數(shù)、浮點(diǎn)數(shù)等都要對(duì)其進(jìn)行編碼,只是這個(gè)編碼是在硬件層的(CPU指令),而計(jì)算機(jī)要與人進(jìn)行交互就要對(duì)人所能識(shí)別的文字進(jìn)行編碼,ASCII就在那個(gè)時(shí)候誕生。

            ASCII(American Standard Code for Information Interchange,美國(guó)信息互換標(biāo)準(zhǔn)代碼)

            美國(guó)標(biāo)準(zhǔn)編碼,用于編碼英文字母的編碼方式。它用了0-127的數(shù)字之間來(lái)表示a-z等可見(jiàn)字符和一些控制字符,而這個(gè)字符集的編碼就確定了ASCII字符集,而這個(gè)字符集要想要在計(jì)算機(jī)的二進(jìn)制方式下使用就必須用計(jì)算機(jī)能夠理解的方式來(lái)處理,ASCII使用了一個(gè)計(jì)算機(jī)字節(jié)來(lái)表示這種編碼方式,在C/C++語(yǔ)言中一個(gè)字節(jié)通常我們使用char來(lái)表示。

            GBK

            GBK,大家都知道,漢字內(nèi)碼擴(kuò)展規(guī)范GBK是怎么來(lái)的呢?GBKGB2312擴(kuò)展來(lái)的,GB2312是最早的中文編碼方式。GB2312又是怎么來(lái)的呢?

            計(jì)算機(jī)發(fā)展到80年代在中國(guó)開(kāi)始慢慢的興起。為了能夠讓中國(guó)人能夠更好的使用計(jì)算機(jī)自然要引入中文編碼到計(jì)算機(jī)中。但是引入中文編碼遇到了一個(gè)問(wèn)題,就是ASCII使用一個(gè)字節(jié)(char)來(lái)編碼字符,但是中國(guó)的漢字是肯定不能夠在一個(gè)字節(jié)中表示完全,怎么辦?聰明的中國(guó)人發(fā)現(xiàn)一個(gè)字節(jié)(char)可表示的最大區(qū)間是0-255,而ASCII只使用了0-127,128-255并沒(méi)有使用,那么我們就可以用多個(gè)字節(jié)來(lái)表示中文編碼比如:

            一個(gè)字節(jié)(char)的值是在0-127之間,我們就還是用這個(gè)字節(jié)來(lái)表示ASCII里面的字符,也就是說(shuō)兼容ASCII

            一個(gè)字節(jié)(char)的值是在128-255之間(此處假設(shè)是130),則說(shuō)明它不是在ASCII字符集里面的,那它表示什么字符呢?此種情況下,則要在讀取下一個(gè)字節(jié)(char)的值(此處假設(shè)是10),那么就將兩個(gè)字節(jié)的值:13010按照某種計(jì)算規(guī)則來(lái)計(jì)算等到一個(gè)值,此處計(jì)算得到3290,那么這個(gè)值可以在一個(gè)字符編碼表中去查,它可能得到某個(gè)漢字,此處假設(shè)為‘字’字然后就可以在屏幕上顯示出來(lái)了。

            (此處的計(jì)算都是假設(shè),我沒(méi)有詳細(xì)查,以后有時(shí)間再更正,理解原理即可。也可以查看維基百科了解詳細(xì)。

            GBK中有哪些字符?

            GBK是微軟利用GB2312未使用的編碼空間,收入GB13000.1的全部字符制定而來(lái)。GBK是用來(lái)編碼中文漢字的,并且兼容ASCII字符集。GBK中是不是只有簡(jiǎn)體中文呢?

            因?yàn)楹?jiǎn)體漢字和繁體漢字有很大一部分是相同,把常見(jiàn)的幾千個(gè)繁體中文里面的漢字編碼進(jìn)來(lái)也不會(huì)多多少,因此,GBK里面也是有繁體中文漢字的。

            除此之外還有什么,因?yàn)楝F(xiàn)在簡(jiǎn)體和繁體的常見(jiàn)字都編碼了,那日文里面的大多數(shù)文字也都在其中,只需要將日文的平假名和片假名(也就幾十個(gè)字符)編碼進(jìn)來(lái)。

            因此,GBK里面是有常見(jiàn)的簡(jiǎn)體中文、繁體中文、日文等字符在一起的字符集。

            Big5等編碼

            中國(guó)人發(fā)明了多字節(jié)編碼的方式,但是只能編碼中國(guó)漢字(包括簡(jiǎn)繁和日文)。其他國(guó)家和中國(guó)臺(tái)灣想要編碼文字自然就會(huì)采用相似的方式來(lái)編碼,Big5等編碼方式就產(chǎn)生了,它們同樣按照某種計(jì)算方式計(jì)算出值,此處假設(shè)還是3290,但是他們的編碼表和GBK不一樣,所以他們代表的文字就不在是‘字’了。

            Windows ANSI編碼

            GBK、Big5等編碼就是ANSI編碼,也叫本地碼。ANSI編碼就是本地碼的統(tǒng)稱,就是在什么國(guó)家或地區(qū)就是什么編碼比如在中國(guó)的大陸地區(qū)就是GBK,在中國(guó)臺(tái)灣就是Big5

            亂碼

            亂碼,很常見(jiàn)也很煩的一個(gè)Bug,編碼Bug

            假設(shè)我們?cè)诤?jiǎn)體中文的機(jī)器上,那么本地碼是GBK,我們用它編碼了一文字保存在txt文件里面,然后把它拷貝到繁體中文的機(jī)器上,此處的本地碼是Big5,然后打開(kāi)這個(gè)文件,假設(shè)我們使用記事本打開(kāi),它打開(kāi)文件使用的默認(rèn)編碼就是本地碼,即Big5,按照Big5的方式計(jì)算值,并依次查字符編碼表,然后顯示出來(lái)。亂碼來(lái)了,本來(lái)在GBK中編碼的有意義的字句,在Big5下計(jì)算查表出來(lái)得到的是一文字字符,而這文字字符連接在一起沒(méi)有任何意思,因此亂碼。

            亂碼和字體

            亂碼是編碼引起的,而在文字顯示中是要去字體中查詢到某個(gè)字符的形狀,然后顯示,有可能出現(xiàn)字體里面沒(méi)有這個(gè)文字,那么就會(huì)用一個(gè)默認(rèn)的字符顯示,此時(shí)給人的感覺(jué)也像亂碼,通常表現(xiàn)出很多個(gè)字符都是一個(gè)樣子(比如一個(gè)白框),但是它不是亂碼,只是字體中沒(méi)有文字的信息,換個(gè)字體就能顯示。

            UNICODE

            隨著互聯(lián)網(wǎng)的發(fā)展,各個(gè)國(guó)家基本上都有自己的本地編碼ANSI編碼。為此,系統(tǒng)要支持多過(guò)的本地編碼,怎么辦?引入代碼頁(yè)code page,根據(jù)代碼頁(yè)號(hào)去查相應(yīng)的字符集,GBK的代碼頁(yè)就是CP936(有細(xì)微差別,詳細(xì)可以查看維基百科)

            但是代碼頁(yè)還是不能將不同字符集中的字符在同一系統(tǒng)中顯示,比如:漢字和阿拉伯文不能同時(shí)顯示。UNICODE誕生了。

            UNICODE就是要將所有的字符全部編碼在一個(gè)字符集里面,比如1-10000編碼簡(jiǎn)體中文,10001-20000編碼繁體中文,依次類推,這樣就構(gòu)成了UNICODE字符集。但是UNICODE字符集并沒(méi)說(shuō)要怎么編碼,只是說(shuō)某個(gè)數(shù)字代表某個(gè)字符,即之規(guī)定了數(shù)字到字符的的字典,但是沒(méi)有規(guī)定在計(jì)算機(jī)中怎么編碼。

            UCS(Universal Character Set)/UTF(Unicode transformation format)

            為了在計(jì)算機(jī)中編碼字符,就出現(xiàn)了UCS/UTF編碼,常見(jiàn)的有UTF-8UTF-16UCS-2),UTF-32UCS-4)編碼。

            UTF-8是類似GBK編碼的一種編碼,就是用多個(gè)字節(jié)編碼計(jì)算出值然后查表,它可以是一個(gè)字節(jié)(也就是兼容ASCII)表示一個(gè)字符,可以是兩個(gè)、三個(gè)、四個(gè)或者更多個(gè)字節(jié)根據(jù)計(jì)算得到某個(gè)值,然后去查UNICODE表得到某個(gè)字符,這樣就將所有字符進(jìn)行了編碼。

            UTF-16則至少是需要兩個(gè)字節(jié)來(lái)表示,也就是說(shuō),可以由兩個(gè)字節(jié)計(jì)算得到某個(gè)值,也可以是四個(gè)字節(jié)、六個(gè)字節(jié)、八個(gè)字節(jié)計(jì)算出值然后查表得到字符。

            UTF-32則至少是需要四個(gè)字節(jié)表示,以此類推

            C/C++中的編碼

            char在C/C++中表示一個(gè)字節(jié),通常也用它來(lái)表示編碼字符,如果它編碼的字符是ASCII編碼,則是每個(gè)字節(jié)都表示一個(gè)字符,也就是說(shuō)每個(gè)char表示一個(gè)字符。如果編碼是ANSI,此處假設(shè)是GBK編碼,那么可以是一個(gè)char表示的字符,也可以是兩個(gè)char表示一個(gè)字符。如果是UTF-8編碼,那么可以是一個(gè)char、兩個(gè)char、三個(gè)char或者更多來(lái)表示一個(gè)字符。

            wchar_t是C/C++中的寬字符,標(biāo)準(zhǔn)沒(méi)有規(guī)定它占幾個(gè)字節(jié),只是規(guī)定用來(lái)編碼unicode字符集,一個(gè)wchar_twindowswchar_tUTF-16編碼)下面占2個(gè)字節(jié),在linuxwchar_tUTF-32編碼)下面占4個(gè)字節(jié),用wchar_t來(lái)編碼unicode的話,常見(jiàn)字符都可以用一個(gè)wchar_t來(lái)表示。但是unicode字符集一直在擴(kuò)充引入更多的字符,所以很有可能一個(gè)wchar_twindows)不能表示出80001號(hào)字符,那么也就出現(xiàn)兩個(gè)wchar_t表示一個(gè)字符,這也就正好符合UTF-16編碼的規(guī)則。

            C/C++中的亂碼解決方法

            亂碼其實(shí)是無(wú)解的。大多數(shù)軟件的軟件的處理方式就是只處理UNICODEUTF-8ANSI編碼,因此一段文字的ANSI編碼和打開(kāi)機(jī)器的本地碼不一樣那么就必然出現(xiàn)亂碼,當(dāng)然若人為的告訴軟件說(shuō)這段文字是某個(gè)code page編碼的,那么還是可以正確顯示,但是這是依靠人為操作了。

            軟件里面處理這個(gè)問(wèn)題處理的最好的有一類軟件,就是瀏覽器。瀏覽器檢測(cè)文本編碼的方式通常就是猜,猜它是哪種編碼,猜完是哪種編碼之后就用相應(yīng)的code page去查字符,然后顯示。那么這個(gè)猜是不是亂猜呢?不是,是通過(guò)逐個(gè)字節(jié)掃描進(jìn)行統(tǒng)計(jì),看看這段文本最可能是哪種編碼。當(dāng)然這樣做也會(huì)有錯(cuò)誤,那么也一樣會(huì)出現(xiàn)亂碼,但是已經(jīng)出現(xiàn)亂碼的幾率很低了。(想詳細(xì)了解可以查看firefoxchrome的源碼)

            看不懂比亂碼好

            假設(shè)一個(gè)程序是用的是GBK編碼的字符串,那么在一個(gè)日文操作系統(tǒng)(Windows)上,軟件的字符那將是亂碼,這給人一個(gè)很不好的感受。即使此軟件沒(méi)有日文版,但是如果能夠?qū)⒑?jiǎn)體中文正確的顯示出來(lái)那還是要好上許多的,說(shuō)不定使用軟件的人還是個(gè)懂中文的人。

            C++里怎么做?Windows從NT開(kāi)始就支持寬字符版本的API,對(duì)于所有使用API的地方都是用寬字符版本就能夠正常的顯示出文字了,在C++中就是使用wchar_t。比如:

            wchar_t *wstr = L"中文";

            然后用對(duì)應(yīng)的寬字符版本的API來(lái)顯示出來(lái)就可以了。那是不是程序內(nèi)部全部都應(yīng)該使用wchar_t來(lái)表示字符?我個(gè)人推薦只在Windows下運(yùn)行的程序這么做,也就是跟字符顯示不相關(guān)的東西也使用wchar_t來(lái)表示。當(dāng)然,也可以根據(jù)情況在只在顯示字符的時(shí)候通過(guò)調(diào)用MultiByteToWideChar將其它編碼的字符轉(zhuǎn)換成寬字符來(lái)顯示,這樣顯示不相關(guān)的字符就可以使用多字節(jié)字符集(ANSI、UTF-8)了。

            對(duì)于跨平臺(tái)的軟件(Windows、Linux),我個(gè)人推薦使用UTF-8編碼的字符來(lái)作為內(nèi)部處理的字符,這樣在只需要在字符顯示的地方轉(zhuǎn)換成相應(yīng)的編碼就可以了。當(dāng)然主要還是在Windows上面做處理,調(diào)用MultiByteToWideChar將UTF-8轉(zhuǎn)換成寬字符然后顯示。

            UTF-8在C++ 98中的表示

            在目前的C++標(biāo)準(zhǔn)中,我們通常不能直接在代碼里面寫(xiě)出UTF-8編碼的字符串常量。

            char *str = "中文"; // 對(duì)于VS,只有源文件是不帶BOM的UTF-8編碼時(shí)才是UTF-8字符串,對(duì)于帶BOM的UTF-8編碼或者GBK編碼的文件都是GBK的字符串;
                                // 對(duì)于GCC,源文件編碼是什么那么這個(gè)字符串的編碼就是什么。

            wchar_t *wstr = L"中文"; // 這里使用的是unicode編碼

            但是,因?yàn)锳NSI編碼和UTF-8編碼都是兼容ASCII編碼的,所以我們可以在代碼里面這樣寫(xiě):

            char *str = "abc";  // 此處的編碼是ASCII、ANSI、UTF-8

            也就是上面這段字符是可以當(dāng)成ANSI編碼也可以當(dāng)成是UTF-8編碼的,那么我們就可以將它當(dāng)成UTF-8編碼來(lái)使用。所以在代碼里面最好不要出現(xiàn)字母以外的字符。(當(dāng)然,不考慮多語(yǔ)言版的話除外

            那我們要與用戶交互的時(shí)候不能是英文字母啊我們可以從資源文件中讀取,即我們可以將要顯示的字符放置到ini、XML以及其它文本文件中,這些文件以UTF-8編碼。這樣我們程序就從資源文件中讀取這些UTF-8編碼的字符就可以了。這也就可以很好的做多語(yǔ)言版本了,只要將資源文件中的字符改成其它語(yǔ)言的字符就可以了,當(dāng)然編碼還是UTF-8。(Windows下窗口相關(guān)的資源.rc也使用UNICODE編碼就行)

            這樣做值得么?值得不值得就看我們的程序是不是需要做多語(yǔ)言版,或者將來(lái)要不要做多語(yǔ)言版,如果要,這就是值得的,不要當(dāng)然就無(wú)所謂了。

            UTF-8在C++ 11中的表示

            C++ 98中不能寫(xiě)出UTF-8、UTF-16、UTF-32的字符串常量,C++ 11加入了新字符類型char16_t和char32_t,其相應(yīng)的常量表示如下:

            u8"中文"; // 表示用UTF-8編碼的字符串常量

            u"中文";  // 表示用UTF-16編碼的字符串常量

            U"中文";  // 表示用UTF-32編碼的字符串常量

            posted on 2012-12-23 13:44 airtrack 閱讀(4533) 評(píng)論(0)  編輯 收藏 引用

            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            久久久久黑人强伦姧人妻| 欧美熟妇另类久久久久久不卡| 久久天天躁狠狠躁夜夜躁2O2O | 久久精品国产91久久麻豆自制| 久久人人妻人人爽人人爽| 久久成人精品视频| 久久国产亚洲精品| 免费无码国产欧美久久18| 亚洲国产精品一区二区久久hs| 精品久久久久久久久午夜福利| 岛国搬运www久久| 久久无码人妻一区二区三区| 久久精品一区二区三区不卡| 日日狠狠久久偷偷色综合0| 久久精品国产亚洲AV无码麻豆| 久久精品国产亚洲7777| 亚洲AV无一区二区三区久久| 国产女人aaa级久久久级| 久久久久亚洲AV无码专区体验| 久久成人精品| 久久国产精品成人免费| 老男人久久青草av高清| 久久精品一区二区三区中文字幕 | 精品国产乱码久久久久久人妻| 国产精品综合久久第一页| 久久中文骚妇内射| 亚洲精品第一综合99久久| 久久久国产精华液| 91久久精品国产免费直播| 91精品国产91久久综合| 久久久精品2019免费观看| 亚洲欧美伊人久久综合一区二区| 久久精品国产精品亜洲毛片 | 国产A三级久久精品| 久久午夜无码鲁丝片午夜精品| 国产巨作麻豆欧美亚洲综合久久| 狠狠色丁香婷综合久久| 精品久久久久久中文字幕| 久久99国产精品99久久| 伊人久久大香线焦综合四虎| 久久综合欧美成人|