版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
EBCDIC[2]的人感覺是腦子進(jìn)了水,哦不,進(jìn)了穿孔卡片了;難怪它和IBM的那些過時老古董一起已經(jīng)幾乎遺忘)。時至今日,ASCII可以看作是字符編碼的基礎(chǔ),主要的編碼方式都保持著與ASCII的兼容性。ACII里只有基本的拉丁字母,它既沒有帶變音符的拉丁字母(如é和?),也不支持像希臘字母(如α)、西里爾字母(如н)(也難怪,畢AmericantandardodeforInormatnInteISO6ISO/IEC9系列等等;大部分編碼方式都是頭個ASCII兼容,后8個字符是自己的擴(kuò)展,總共最多是6個字符。每次只有一套方式可以生效,稱之為一個代碼頁(codepage)。這種做法,只能適用于文字相近、且字符數(shù)不多的國家。比如,下圖表示了O-889-1(也稱作tn-)和后面的Windows擴(kuò)展代碼頁5(下圖中綠框部分為Windows的擴(kuò)展),就只能適用于西歐最早的中文字符集標(biāo)準(zhǔn)是1980年的國標(biāo)GB2312[3],其中收錄了6763個常用漢字和682個其他符號。我們平時會用到編碼GB2312,其實更正確的名字是 一種與ASCII兼容的編碼方式。它用單字節(jié)表示ASCII字符而用雙字節(jié)表示GB2312中的字符;由于GB2312中本身也含有ASCII中包含的字符,在使用中逐漸就形成了“半GBK[5],Windows標(biāo)準(zhǔn)編碼方式。GB2312和GBK所占用的編碼位置可以參看下面的圖(由JohnM.D?ugosz為Wikipedia繪制):GBK/1GBK/2GB2312于1991—1992年。由于最初發(fā)明者的目標(biāo)放得太低,只期望對活躍使用中的現(xiàn)代文字進(jìn)行編碼,他們認(rèn)為16比特的“寬ASCII”就夠用了。這就導(dǎo)致了早期采納Unicode的組織,特別是微軟,在其操作系統(tǒng)和工具鏈中廣泛采用了16比特的編碼方式。在今天,微軟的系統(tǒng)中寬字符類型wchar_t仍然是16位的,操作系統(tǒng)底層接口大量使用16位字符編碼的API,說到Unicode編碼時仍然指的是16位的編碼UTF-16(這一不太正確的名字,跟中文GBK編碼居然可以被叫做ANSI相比,實在是小巫見大巫了)。在微軟以外的世界,Unicode本身不作編碼名稱用,并且最主流的編碼方式并不是UTF-16,而是和ASCII全兼容的UTF-8早期Uniode組織的另一個決定是不同語言里的同一個字符使用同一個編碼點,來減少總編碼點的數(shù)量。韓三國使用的漢字就這么被統(tǒng)一了:像“將、“徑、“網(wǎng)等字,每個字在Uniode中只占一個編碼點。這對網(wǎng)頁的字體選擇也造成了不少麻煩,時至今日我們?nèi)匀豢梢钥吹竭@個問題[]。不過這和我們的無關(guān),就不再多費(fèi)筆墨了。UnicodeUnicode在今天已經(jīng)大大超出了最初的目標(biāo)。到Unicode12.1為止,Unicode已經(jīng)包含了137,994個字符,囊括所有主要語言(使用中的和已經(jīng)不再使用的),并包含了表情符號、數(shù)學(xué)符號等各種特殊字符。仍然要一下,Unicode字符是根據(jù)含義來區(qū)分的,而非根據(jù)字形。除了前面提到過韓漢字沒有分開,像斜體(italics)、小大寫字母smallcaps)等排版效果在Uniode里也沒有獨立的對應(yīng)。不過,因為Unode里包含??????(但不適合嚴(yán)肅的排版)。Unicode的編碼點是從0x0到0x10FFFF,一共1,114,112個位置。一般用“U+”后面跟16進(jìn)制的數(shù)值來表示一個Unicode字符,如U 表示空格,U+6C49表示“漢”,U+1F600表示“??”,等等(不足四位的一般寫四位)。UnicodeUTF-16[8]:對于從U 到U+FFFF的字符,使用16比特的直接映射;對于大于U+FFFF的字符,使用32比特的特殊映射關(guān)系——在Unicode的16比特編碼點中0xD800–0xDFFF是一段空隙,使得這種變長編碼成為可能。在一個UTF-16的序列0xD800–0xDBFF3216內(nèi)容是0xDC00–0xDFFF,那這是32比特編碼的后16比特;如果內(nèi)容在0xD800–0xDFFF之外,那就是一個16比特的映射。UTF-8[9]:1到4UTF-8節(jié)的最是0,那就是一個單字節(jié)的Unicode字符;如果一個字節(jié)的最高兩比特是10,那這是一個Unicode字符在編碼后的后續(xù)字節(jié);否則,這就是一個Unicode字符在編碼后的首字節(jié),且最開始連續(xù)1的個數(shù)表示了這個字符按UTF-8的方式編碼有幾個在上面三種編碼方式里,只有F-8完全保持了和ACII使用。在我們下面講具體編碼方式之前,我們先看一下上面提到的三個字符在這三種方式下的編碼結(jié)果: 映射為 ,U+6C49映射為0x00006C49,U+1F600射為0x0001F600 0x0020,U+6C490x6C49U+1F600 0x20,U+6C490xE6B189U+1F6000xF09F9880Unicode有好幾種(上面還不是全部)不同的編碼方式,上面的16比特和32比特編碼方式還有小頭黨和大頭黨之爭(“漢”按字節(jié)時是6C49呢,還是496C?);同時,任何一種編碼方式還需要跟傳統(tǒng)的編碼方式容易區(qū)分。因此,Unicode文本文件通常有一個使用BOM(byteordermark)字符的約定,即字符U+FEFF[11]。由于Unicode不使用U+FFFE,在文件開頭加一個BOM即可區(qū)分各種不同編碼:如果文件開頭是0x0000FEFF,那這是大頭的UTF-32編碼否則如果文件開頭是0xFFFE0000,那這是小頭的UTF-32編碼;否則如果文件開頭是0xFEFF,那這是大頭的UTF-16編碼;否則如果文件開頭是0xFFFE,那這是小頭的UTF-16編碼(注意,這條規(guī)則和第0xEFBBBFUTF-8編輯器可以(有些在配置之后)根據(jù)BOM字符來自動決定文本文件的編碼。比如,我一般在Vim中配置setfileencodings=ucs-bom,utf-8,gbk,latin1。這樣,Vim在讀入文件時,會首先檢查BOM字符,有BOM字符按BOM字符決定文件編碼;否則,試圖將文件按UTF-8來(由于UTF-8有格式要求,非UTF-8編碼的文件通常會導(dǎo)致失?。?;不行,則試圖按GBK來(失敗的概率就很低了);還不行,就把文件當(dāng)作Latin1來處理(不會失敗)。UTF-8BOMUnixWindowsBOMUTF-8C++中的UnicodeC++98中有char和wchar_t兩種不同的字符類型,其中char的長度是單字節(jié),而wchar_tWindowsUTF-16,Unix般是四字節(jié),可以代表UTF-32。為了解決這種,目前我們有了下面的改進(jìn):C++11char16_tchar32_t兩個獨立的字符類型(不是類型別名),分別代表UTF-16和UTF-32。stringwstringu16string、u32string(和將來的除了傳統(tǒng)的窄字符/字符串字面量(如"hi")和寬字符/字符串字面量(如L"hi"),UTF-8、UTF-16UTF-32u8"hi"、u"hi"和U"hi"。ASCIIUnicode如,我們前面說到的三個字符可以這樣表達(dá)成一個UTF-32字符串字面量:U"\u6C49\U0001F600"UTF-16或UTF-8使用這些新的字符(串)UTF-32UTF代代123456789#include<iomanip>#include<iostream>#include<stdexcept>#includeusingnamespaceconstchar32_tunicode_max=voidto_utf_16(char32_tu16string&{if(ch>unicode_max)throw"invalidcode}if(ch<0x10000)result+=}elsechar16_tfirst0xD800((ch-0x10000)>>char16_tsecond0xDC00|(ch&result+=result+=}}voidto_utf_8(char32_tstring&{if(ch>unicode_max)throw"invalidcode}if(ch<0x80)result+=}elseif(ch<0x800)result+=0xC0|(ch>>result+=0x80|(ch&}elseif(ch<0x10000)result+=0xE0|(ch>>result0x80|((ch>>6)&result+=0x80|(ch&}elseresult+=0xF0|(ch>>result0x80|((ch>>12)&result0x80|((ch>>6)&result+=0x80|(ch&}}int{ char32_tstr[] U" u16stringstringfor(autoch:{if(ch==0){}to_utf_16(ch,u16str);to_utf_8(ch,u8str);}cout<<hex<<setfill('0');for(char16_tch:u16str)cout<<setw(4)<<<<'}cout<<for(unsignedcharch:{cout<<setw(2)<<<<'}}00206c49d83d20e6b189f09f98下面我們看一下在兩個主流的平臺上一般是如何處理Unicode編碼問題的?,F(xiàn)代Unix系統(tǒng),包括Linux和macOS在內(nèi),已經(jīng)全面轉(zhuǎn)向了UTF-8。這樣的系統(tǒng)中一般直接使用char[]和string來代表UTF-8字符串,包括輸入、輸出和文件名,非常簡單。不過,由于一個字符單位不能代表一個完整的Unicode的場合轉(zhuǎn)換到UTF-32往往會更簡單。在以前及需要和C兼容的場合,會使用wchar_t、uint32_t或某個等價的類型別名;在新的純C++代碼里,就沒有理由不使用char32_t和u32string了。Unix下輸出寬字符串需要使用wcout(這點和Windows相同),并且需要進(jìn)行區(qū)域設(shè)setlocale(LC_ALL,"en_US.UTF-8");即足夠。由于沒有什么額外好處,Unix平臺下一般只用cout,不用wcout。Windows由于歷史原因和保留向后兼容性的需要(Windows為了向后兼容性已經(jīng)到了大規(guī)模放棄優(yōu)雅的程度了),一直用hr表示傳統(tǒng)編碼(如,英文WindowsWindows-5,簡體中文WindowsGBK,用hatF-1。由于傳統(tǒng)UTF-。代12345#includete<typenamevoiddump(constT&{Windows(串)是最簡單的處理方式。當(dāng)然,源代碼和文用F-16,通常還是F-(除非是純ACII,否則需要加入BOM和傳統(tǒng)編碼相區(qū)分)ASCII字符轉(zhuǎn)換成傳統(tǒng)編碼。換句話說,同樣的源代碼在不同編Windows代12345#includete<typenamevoiddump(constT&{6(charch:7{8"%.2x9static_cast<unsigned}}int{charstr[]"你好charu8str[]u8"你好}Windowsc4e3bac3e4bda0e5a5bdWindows下的wcout主要用在配合寬字符的輸出,此外沒什么大用處。原因一樣,只有進(jìn)行了正確的區(qū)域設(shè)置,才能輸出含非ASCII字符的寬字符串。如果要輸出中文,得寫setlocale(LC_ALL," 由于窄字符在大部分Windows系統(tǒng)上只支持傳統(tǒng)編碼,要打開一個當(dāng)前編碼不支持的文件名稱,就必需使用寬字符的文件名。微軟的tem系列類及其enntwcrt*類型的文件名,這是C++微軟推薦的方式一般是前者。做Windowstchar.h和_T起著類似的作用(雖然目的不同)。根據(jù)預(yù)定義宏的不同,系統(tǒng)會在同一套代碼下選擇不同的編碼方式及對應(yīng)的函數(shù)。拿一個最小的例子來說:代代1234567#include#includeint_tmain(intargc,TCHAR*{o}代代123456#includeintmain(intargc,char*{o}而如果在命令行上加上了/D_UNICODE代代123456#includeintwmain(intargc,wchar_t*{o}當(dāng)然,這個代碼還是只能在Windows上用,并且仍然不漂亮(所有的字符和字符串字面量都得套上_)。后者無解,前者則可以找到替代方案(甚至自己寫也不復(fù)雜)。C++RESTKWindows的開發(fā)方式。相應(yīng)的,對Unix開發(fā)者而言更自然的方式是全面使用F-8,打交道時把字符串轉(zhuǎn)換成需要的編碼。利用臨時對象的生命周期,我們可以像下面這樣寫幫助函數(shù)和宏。代代1234567#ifndef#define#include#ifdefined(_WIN32)||\代1代123456789#include#ifdefined(_WIN32)||\#include<windows.h>#include<system_error>namespacethrow_system_error(constchar*reason){std::stringmsg+="failed";std::error_codeec(89utf8_to_wstring(constchar*str);std::wstring#defineNATIVE_STR(s)\inlineconstchar*to_c_str(constchar*str){return}inlineconstchar*to_c_str(conststd::string&str){return}#defineNATIVE_STR(s)\#endif//19
throwstd::system_error(ec,21}/*unnamednamespace23std::wstring25
constchar*intlen= CP_UTF8,0,str,- nullptr, if(len==0) std::wstringresult(len- if CP_UTF8,0,str,-result.data(),len)==0) 42
returnstd::wstringconststd::string&46return4951在頭文件里,定義了在Windows下會做UTF-8到UTF-16的轉(zhuǎn)換;在其他環(huán)境下則不真正做轉(zhuǎn)換,而是不管提供的是字符指針還是string都會轉(zhuǎn)換成字符指針。在WindowsNATIVE_STR會生成一個臨時對象,當(dāng)前語句執(zhí)行結(jié)束后這個臨時對象會自動代代#include#include33456789int{usingnamespacestd;constcharfilename[]=ifstream//ifs}UnixWindows(任何語言設(shè)置下),用來讀Unicode及其轉(zhuǎn)換的APIWindows上一節(jié)的代碼在Windows下用到了MultiByteToWideChar[12],從某個編碼轉(zhuǎn)到UTF-16。WindowsWideCharToMultiByte[13UTF-16個編碼。從上面可以看到,C接口用起來并不方便,可以考慮自己封裝一下。Unixiconv[14],提供iconv_open、iconv_closeiconvCICU[15]是一個完整的Unicode,ICU4CC/CICU有專門的字符串類型,內(nèi)碼是UTF-,但可以直接用于Ostrams的輸出。下面的程序應(yīng)該在所有平臺上都有同樣的輸出(但在Windows上要求當(dāng)前系統(tǒng)傳統(tǒng)編碼能支持待輸出的字符):代代#include#include33456789#include#includeusingnamespacestd;usingicu::UnicodeString;int{autostr=UnicodeString::fromUTF8(u8"你好cout<<str<<endl;stringu8str;cout<<"InUTF-8itis"<<u8str.size()<<"<<C+11曾經(jīng)引入了一個頭文件<odet>[16]F編碼間的轉(zhuǎn)換,但很遺憾,那個頭文件目前已因為存在安全性和易用性問題被放棄(depred[1<locale>中有另外一個det[],本身接口不那么好用,而且到C++0有的話可以直接看參考資料。Unicode,C++Unicode面平臺上關(guān)于
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024版建筑鋼結(jié)構(gòu)主要工程承包協(xié)議版B版
- 2024年高速公路安全欄桿施工合同
- 2024旅游公司旅游服務(wù)合同
- 二零二五年度便利店特許經(jīng)營加盟合同范本3篇
- 油藏課程設(shè)計問題
- 二零二五年度辦公室租賃及綠色環(huán)保措施合同3篇
- 2024年物業(yè)環(huán)境保護(hù)管理合同3篇
- 2025年度砂石料設(shè)備采購與智能化控制合同3篇
- 二零二五年度交通基礎(chǔ)設(shè)施建設(shè)財政資金股權(quán)投資委托管理協(xié)議3篇
- 2024版寵物狗食品合同全編3篇
- 蛋雞養(yǎng)殖場管理制度管理辦法
- 螺內(nèi)酯在腎臟病中的應(yīng)用演示教學(xué)
- 市政工程計量與計價講義
- 建筑工程設(shè)計過程控制流程圖
- T∕CRIA 20002-2021 炭黑原料油 煤焦油
- 小孩出生后視力發(fā)展過程
- X62W萬能銑床
- 供應(yīng)商年度審核計劃及現(xiàn)場審核表
- 環(huán)甲膜穿刺ppt課件
- 裝配基礎(chǔ)知識要點
- 電腦全自動插拔力試驗機(jī)操作指導(dǎo)書
評論
0/150
提交評論