青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Windows API 字符編碼轉換以及一些解釋和心得

我在解決亂碼上面實際走了不少彎路,做了很多實驗,查了很多資料。在這里做下筆記,希望后來者可以明白,少走些彎路。

從最熟悉的兩種字符編碼說起

除了一些舊的、沒有考慮到兼容性的網頁還在用gbk做編碼外,大部分的網頁都已經用utf-8做編碼了。但是最令人頭疼的是,windows的控制臺是很不好顯示utf-8的。有明君為我大C++寫了兩個函數,是正確的、好用的(除了用std::string做返回值讓我等效率黨有點覺得不爽之外……還是挺方便的).

#include <string>
#include 
<windows.h>
using std::string;

//gbk 轉 utf8
string GBKToUTF8(const string& strGBK)
{
    
string strOutUTF8 = "";
    WCHAR 
* str1;
    
int n = MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, NULL, 0);
    str1 
= new WCHAR[n];
    MultiByteToWideChar(CP_ACP, 
0, strGBK.c_str(), -1, str1, n);
    n 
= WideCharToMultiByte(CP_UTF8, 0, str1, -1, NULL, 0, NULL, NULL);
    
char * str2 = new char[n];
    WideCharToMultiByte(CP_UTF8, 
0, str1, -1, str2, n, NULL, NULL);
    strOutUTF8 
= str2;
    delete[]str1;
    str1 
= NULL;
    delete[]str2;
    str2 
= NULL;
    
return strOutUTF8;
}

//utf-8 轉 gbk
string UTF8ToGBK(const string& strUTF8)
{
    
int len = MultiByteToWideChar(CP_UTF8, 0, strUTF8.c_str(), -1, NULL, 0);
    unsigned 
short * wszGBK = new unsigned short[len + 1];
    memset(wszGBK, 
0, len * 2 + 2);
    MultiByteToWideChar(CP_UTF8, 
0, (LPCTSTR)strUTF8.c_str(), -1, wszGBK, len);

    len 
= WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL);
    
char *szGBK = new char[len + 1];
    memset(szGBK, 
0, len + 1);
    WideCharToMultiByte(CP_ACP,
0, wszGBK, -1, szGBK, len, NULL, NULL);
    
//strUTF8 = szGBK;
    std::string strTemp(szGBK);
    delete[]szGBK;
    delete[]wszGBK;
    
return strTemp;
}

這玩意兒不跨平臺,因為它用到了windows api。我之所以把它放到跨平臺編程上面來,是因為字符編碼這東西只有到跨平臺的時候才顯得坑爹。


接著我是不是要介紹那倆函數一下?

int MultiByteToWideChar(
  _In_       UINT CodePage, 
/*代碼頁是Windows下字符編碼的叫法,gbk是936,utf-8是65001,CP_ACP是ANSI*/
  _In_       DWORD dwFlags, 
/*選項標志,轉換類型,設0就行了*/
  _In_       LPCSTR lpMultiByteStr, 
/*多字節字符串*/
  _In_       
int cbMultiByte, /*字符串要處理的長度,如果是-1函數就會處理整個字符串*/
  _Out_opt_  LPWSTR lpWideCharStr, 
/*輸出的寬字符串緩存,如果為空就返回需要的寬字符串長度*/
  _In_       
int cchWideChar /*寬字符串緩存的長度,當然如果寬字符串為空,這個設0就可以了*/
);

int WideCharToMultiByte(
  _In_       UINT CodePage,
  _In_       DWORD dwFlags,
  _In_       LPCWSTR lpWideCharStr,
  _In_       
int cchWideChar,
  _Out_opt_  LPSTR lpMultiByteStr,
  _In_       
int cbMultiByte, /*前面的基本與MultiByteToWideChar都相同,就不解釋了*/
  _In_opt_   LPCSTR lpDefaultChar, 
/*填0即可*/
  _Out_opt_  LPBOOL lpUsedDefaultChar 
/*填0即可*/
);

這兩個函數分別是將多字節字符串轉換為寬字符字符串 和 將寬字符字符串轉換為多字節字符串(在此處暈倒的童鞋們我沒有對不起你們……是M$那家伙對不起你們)。我早就說過Windows API 的界面不友好,這么多不知道干嘛嗎用的參數,全部填0就對了。要是iconv(),它貌似只有4個參數,這才是好的榜樣。


寬字符?多字節?

這是Windows給它們起的名字,讓人摸不著頭腦。

  • 寬字符:就是Unicode。它雷打不動地用2個字節(0x0000 - 0xFFFF),表示所有我們平常能見到的字符,具體的表格見:http://unicode-table.com

  • 多字節:就是除了Unicode外其他的。我們熟悉的gbk, utf-8, big5,統統歸入多字節。

寬字符之所以叫做寬字符,是因為它是一個寬一點的字符。那什么是短字符……就是ascii了,1個字節1個字符絕對夠短,而且只能表示256個西歐字符。寬字符呢,是2個字節1個字符。寬一點,但還是可以識別到一個字符是哪里的。而多字節呢,就是它在計算機里表示成多個字節,但是沒有辦法識別那里到那里是一個字符。

我不喜歡這兩個函數的命名。如果按照Python的命名,MultiByteToWideChar 應該叫 decode(解碼),WideCharToMultiByte 應該叫 encode(編碼)。


所以呢?

如你所見,多字節無法準確識別字符的長度,處理起來就會很麻煩。而寬字符大多時候雖然比多字節多耗費一點空間,但是處理起來方便。比如正則表達式處理,引擎是基于字符去匹配的,寬字符可以兩個字節兩個字節跳著匹配,而多字節就會匹配錯誤。

比如有一個詞“程序”=0xB3CCD0F2(gbk),我想匹配“”=0xCCD0(gbk),正則庫會替我把中間那兩個字節匹配了。用在C里用wchar_t,C++里用std::wstring,我們可以很準確的,無錯誤地匹配到我們想要的子串,因為引擎在迭代的時候是逐字(而不是逐字節)進行比較的。

1 >>> str1 = ""
2 >>> str2 = "程序"
3 >>> print re.findall(str1, str2)
4 ['\xcc\xd0']
5 >>> print re.findall(str1.decode("gbk"), str2.decode("gbk"))
6 []

所以在處理字符串的時候,但凡要處理中文,要先把用戶給的字符串解碼成Unicode。處理完之后顯示出來或者保存,再編碼成需要的charset。


Appendix

在不同的地方用不同的編碼:

  • 網絡文本(如網頁)傳輸一般用utf-8,因為有少量中文,而大部分是英文。
  • 在保存為本地文件的時候,應該保存為Unicode,因為本地存儲資源豐富,且可以節省時間,實時解碼畢竟也是O(N^2)啊。
  • 顯示出來應該用系統的編碼,中文Windows為gbk,繁體Windows為Big5,Linux一律為UTF-8。
  • 源代碼里的少量中文串盡量用"\x????\x????"來表示,如果有大量中文建議用gettext或者資源之類的以外掛的方式讀入。
  • Qt內部使用Unicode,所以編寫Qt應用時顯示文字直接傳遞寬字符串即可。
  • NTFS的文件名、路徑都是用GBKUTF16LE編碼的,所以如果Windows下用戶輸入的是路徑就無需解碼了。


posted on 2013-10-28 22:49 Shihira 閱讀(7267) 評論(8)  編輯 收藏 引用 所屬分類: 跨平臺編程

評論

# re: Windows API 字符編碼轉換以及一些解釋和心得[未登錄] 2013-10-29 12:45 jacky

string作為返回值也沒什么大問題,現代編譯器(返回值優化,右值引用)都能優化掉多余的拷貝。  回復  更多評論   

# re: Windows API 字符編碼轉換以及一些解釋和心得 2013-10-29 13:52 Shihira

@jacky
謝謝提醒,即將更正。  回復  更多評論   

# re: Windows API 字符編碼轉換以及一些解釋和心得[未登錄] 2013-10-30 10:07 春秋十二月

那兩個函數和我代碼庫中的差不多哈  回復  更多評論   

# re: Windows API 字符編碼轉換以及一些解釋和心得 2013-11-08 10:38 海邊泡沫

樓主還是沒有理解寬字符和多字符的本質。
它們的本質絕對不是為了儲存,而是為了溝通。
從儲存的角度講,我們可以用一個字符表示一個字母,也可以用兩個字節表示一個字母和漢字,也可以用三個、四個字符。所以不管是UNICODE也好,還是GBK、BIG5也好,它們沒有本質的區別,它們的本質都是固定寬度的。而從溝通的角度講,只要知道這些固定寬度的字節串的采取的是什么編碼,就可以相互轉換。
從儲存的角度講,既然都是固定寬度的,我們其實不僅可以用wchar[]來儲存UNICODE,也可以用wchar[]來儲存BIG5或GBK。而事實上,除了UNICODE,Windows中其它的所有編碼儲存都是用char[],包括UTF-8。這也是為什么WINDOWS中的轉換函數叫MultiByteToWideChar了,這一組函數意義很明確,不存在設計問題。
那么還有用char[]的必要嗎?難道這只是歷史遺留問題嗎?當然不是了。這也是我要說的溝通的本質了。
從溝通的本質講,我們在計算機中和網絡上所傳輸的、所比較的,一切的本質都是字節流,嚴格來說,是只用到了最低7位,低8位為0的字節流,也就是unsigned char[]。所以網絡上廣范使用UTF-8不是因為它省空間,而是因為它是字節流,是最適合傳輸的表達字符的編碼方案。
UTF-8是寬度不固定的。我認為微軟的專家早就認識到了這個本質,所以不管一種編碼的寬度是否固定,他們都把他們叫MiltiByte,而只有UNICODE叫WideChar。
最后再說一點,從溝通的角度講,不僅字符是字節流,數字也是字節流,而且在傳輸數字的時候還要考慮字節序。這也是hton和ntoh這樣一組函數存在的原因。  回復  更多評論   

# re: Windows API 字符編碼轉換以及一些解釋和心得 2013-11-09 16:41 紅色代碼

windows下的字符轉換確實夠坑爹的  回復  更多評論   

# re: Windows API 字符編碼轉換以及一些解釋和心得 2013-11-26 01:12 放屁阿狗

iconv why not ?  回復  更多評論   

# re: Windows API 字符編碼轉換以及一些解釋和心得 2014-03-04 17:07 huxi

"NTFS的文件名、路徑都是用GBK編碼的,所以如果Windows下用戶輸入的是路徑就無需解碼了。"
貌似NTFS的路徑是UTF16LE編碼,
http://zh.wikipedia.org/wiki/NTFS

文件系統支持最長 32767 個 Unicode 字符的的路徑[57]。但每個路徑組成部分(目錄或文件名)最多只允許包含 255 個字符[57],同時某些特定的名稱需要用于保存 NTFS 將元數據,因此禁止用作普通的文件/目錄名。NTFS 的元數據都存放在卷的根目錄下,因此上文所述的文件名要求也僅限于根目錄。被 NTFS 保留的名稱有:$MFT、$MFTMirr、$LogFile、$Volume、$AttrDef、.(點)、$Bitmap、$Boot、$BadClus、$Secure、$Upcase,以及 $Extend[2]。在這些項目中,.(點)和 $Extend 是目錄類型,其它項目均為文件類型。  回復  更多評論   

# re: Windows API 字符編碼轉換以及一些解釋和心得 2014-03-27 13:50 Shihira

@huxi
It makes sense. 謝謝提醒,已更正.  回復  更多評論   


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


導航

統計

公告

留言簿(2)

隨筆分類

搜索

最新隨筆

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            91久久久久久国产精品| 亚洲精品中文字幕在线| 欧美一级播放| 欧美一区三区二区在线观看| 午夜精品久久久久久| 亚洲天堂免费观看| 新狼窝色av性久久久久久| 欧美一区二区在线视频| 免费成人高清在线视频| 欧美日韩视频一区二区三区| 国产精品视频yy9099| 国产一区二区三区奇米久涩 | 欧美在线观看视频在线| 久久久777| 亚洲国产裸拍裸体视频在线观看乱了中文 | 久久综合九色| 欧美激情一二区| 国产精品美女一区二区| 永久免费精品影视网站| 一区二区三区国产盗摄| 久久精品国产亚洲一区二区三区| 免费一区二区三区| 亚洲无限乱码一二三四麻| 久久精品一二三区| 国产精品红桃| 亚洲美女毛片| 久久手机精品视频| 一本色道久久综合亚洲精品按摩 | 欧美亚洲综合另类| 亚洲国产mv| 欧美在线观看视频一区二区三区| 欧美成人精品高清在线播放| 国产日韩亚洲欧美精品| 亚洲天堂成人| 亚洲第一偷拍| 久久精品官网| 国产精品中文在线| 亚洲高清不卡一区| 亚洲一区二区三区在线播放| 久久精品国产亚洲精品| 日韩一区二区精品| 久久综合久久久久88| 国产九九精品| 亚洲一区二区精品视频| 欧美激情网站在线观看| 欧美影片第一页| 国产精品亚洲а∨天堂免在线| 亚洲区国产区| 欧美电影资源| 久久久久国产成人精品亚洲午夜| 国产精品一区免费在线观看| av不卡在线| 91久久精品www人人做人人爽 | 欧美网站在线观看| 亚洲区欧美区| 亚洲国产精品综合| 免费一级欧美片在线播放| 国内精品写真在线观看| 久久国产成人| 久久久成人网| 在线观看亚洲| 欧美大片在线观看一区二区| 久久精品观看| 亚洲国产一区二区a毛片| 免费成人毛片| 欧美电影免费| 亚洲网站在线| 亚洲午夜免费福利视频| 国产精品日韩一区二区三区| 亚洲欧美国产日韩中文字幕| 亚洲系列中文字幕| 国产欧美日韩在线播放| 久久久久88色偷偷免费| 久久爱www.| 最新中文字幕一区二区三区| 亚洲国产成人在线播放| 欧美人与性动交cc0o| 亚洲欧美制服中文字幕| 久久av资源网| 亚洲精品偷拍| 亚洲欧美国产一区二区三区| 狠狠色丁香久久婷婷综合_中| 欧美国产三级| 国产精品国产三级国产aⅴ无密码 国产精品国产三级国产aⅴ入口 | 国产精品区一区| 久久久久在线| 欧美精品一区在线观看| 亚洲欧美激情一区| 久久久综合香蕉尹人综合网| 日韩视频二区| 欧美在线高清视频| 99在线热播精品免费| 欧美一级黄色网| 国内精品久久久久影院薰衣草| 亚洲欧美激情视频| 黄色一区二区在线| 亚洲精品欧美日韩| 国产亚洲午夜高清国产拍精品| 亚洲丰满少妇videoshd| 国产九区一区在线| 亚洲精品欧美在线| 狠狠色狠狠色综合日日小说| 亚洲美女性视频| 亚洲第一精品夜夜躁人人爽| 亚洲午夜在线观看| 日韩午夜在线电影| 久久久久久久久久看片| 香蕉久久夜色精品国产使用方法| 久久性天堂网| 久久成人免费日本黄色| 欧美精品在线视频| 女同一区二区| 国产欧美一级| 亚洲图片你懂的| 亚洲视频福利| 欧美精品自拍| 亚洲大胆在线| 在线观看视频亚洲| 久久不射网站| 久久人人97超碰国产公开结果| 欧美性猛交xxxx乱大交蜜桃| 亚洲国产精品久久久久久女王| 韩日视频一区| 久久精品国产在热久久| 欧美在线影院| 国产女主播一区二区三区| 一本大道久久a久久综合婷婷| 最新高清无码专区| 欧美777四色影视在线| 欧美成人在线免费观看| 狠狠狠色丁香婷婷综合久久五月| 欧美亚洲综合在线| 久久精品99久久香蕉国产色戒| 国产精品裸体一区二区三区| 日韩午夜在线视频| 亚洲天堂久久| 国产精品免费福利| 亚洲欧美综合精品久久成人| 欧美有码视频| 国产亚洲va综合人人澡精品| 亚洲欧美日韩直播| 欧美一区日本一区韩国一区| 国产精品无码专区在线观看| 亚洲一区免费| 久久久蜜桃一区二区人| 狠狠色伊人亚洲综合网站色| 欧美在线视频免费观看| 蜜臀av性久久久久蜜臀aⅴ四虎| 在线免费观看视频一区| 老司机一区二区| 亚洲精品国产精品乱码不99| 99re8这里有精品热视频免费| 欧美日韩国产限制| 亚洲欧美日韩一区二区三区在线| 久久黄色小说| 亚洲精品欧美日韩| 国产精品久久久久一区二区| 亚洲综合国产激情另类一区| 久久久久国产一区二区| 在线观看欧美日韩国产| 欧美美女操人视频| 亚洲欧美日产图| 国产精品高清网站| 久久精品视频亚洲| 激情视频一区| 欧美激情在线| 亚洲欧美日韩在线一区| 欧美成人免费在线| 亚洲视屏一区| 伊人一区二区三区久久精品| 欧美国产日韩一二三区| 亚洲一区二区在线观看视频| 久久久精品国产免大香伊| 久久免费一区| 亚洲伦理在线| 国产欧美日韩一区二区三区| 久久人体大胆视频| 亚洲免费成人av电影| 久久久国产午夜精品| 亚洲美女视频在线观看| 国产精品麻豆va在线播放| 男人的天堂亚洲| 亚洲自拍电影| 最新日韩在线视频| 久久久久高清| 亚洲欧美欧美一区二区三区| 有坂深雪在线一区| 国产精品素人视频| 欧美美女视频| 久久在线视频在线| 小处雏高清一区二区三区| 日韩亚洲欧美成人| 亚洲国语精品自产拍在线观看| 久久精品系列| 欧美一区高清| 亚洲欧美成人| 亚洲视频axxx| 亚洲性感美女99在线| 最近中文字幕日韩精品| 精品成人在线|