一網打盡中文編碼轉換

一網打盡中文編碼轉換——6種編碼30個方向的轉換

1.問題提出

在學編程序時,曾經有人問過「你可以編一個記事本程序嗎?」當時很不屑一顧,但是隨著學習MFC的深入,了解到記事本程序也並非易事,難點就是四種編碼之間的轉換。

對於編碼,這是一個令初學者頭疼的問題,特別是對於編碼的轉換,更是難以捉摸。筆者為了完成畢業設計中的一個編碼轉換模塊,研究了中文編碼和常見的字符集後,決定解決"記事本"程序的編碼問題,更進一步完成GB2312、Big5、GBK、Unicode 、Unicode big endian、UTF-8共6種編碼之間的任意轉換。

2.問題解決

(1)編碼基礎知識

a.了解編碼和字符集

這部分內容,我不在贅述,可參見CSDN Ancky的專欄中《各種字符集和編碼詳解》

博客地址:http://blog.csdn.net/ancky/article/details/2034809

b.單位元組、雙位元組、多位元組

這部分內容,可參見我先前翻譯的博文《C++字元串完全指南--第一部分:win32字元編碼》

博客地址:http://blog.csdn.net/ziyuanxiazai123/article/details/7482360

c.區域和代碼頁

這部分內容,可參見博客 http://hi.baidu.com/tzpwater/blog/item/bd4abb0b60bff1db3ac7636a.html

d.中文編碼GB2312、GBK、Big5,這部分內容請參見CSDN lengshine 博客中《GB2312、GBK、Big5漢字編碼》,博客地址:http://blog.csdn.net/lengshine/article/details/5470545

e.Windows程序的字元編碼

這部分內容,可參見博客http://blog.sina.com.cn/s/blog_4e3197f20100a6z2.html 中《Windows程序的字元編碼》

(2)編碼總結

a.六種編碼的特點

六種編碼的特點如下圖所示:

b.編碼存儲差別

ANSI(在簡體中文中默認為GB2312)、Unicode、Unicode big endian 、UTF-8存儲存在差別。

以中文"你好"二字為例,他們存貯格式如下圖所示:

c.GB2312、Big5、GBK編碼的區別

三者中漢字均採用二個位元組表示,但是位元組表示的值範圍有所不同,如下圖所示:

(3)編碼轉換方式

6種編碼互相轉換,由排列組合知識知道共有30個方向的轉換.筆者採用的轉換方法,

多位元組文件與Unicode文件轉換如下圖所示:

多位元組文件之間轉換如下圖所示:

(4)編碼轉換使用的三個函數

a.MultiByteToWideChar

該函數完成多位元組字元串向Unicode寬字元串的轉換.

函數原型為:

int MultiByteToWideChar( UINT CodePage, // 代碼頁 DWORD dwFlags, // 轉換標誌 LPCSTR lpMultiByteStr, // 待轉換的字元串 int cbMultiByte, // 待轉換字元串的位元組數目 LPWSTR lpWideCharStr, // 轉換後寬字元串的存儲空間 int cchWideChar // 轉換後寬字元串的存儲空間大小 以寬字元大小為單位);b.WideCharToMultiByte該函數完成Unicode寬字元串到多位元組字元串的轉換,使用方法具體參見MSDN。以上兩個函數可以完成大部分的字元串轉換,可以將其封裝成多位元組和寬位元組之間的轉換函數:[cpp] view plaincopyprint?

  1. wchar_t*Coder::MByteToWChar(UINTCodePage,LPCSTRlpcszSrcStr)
  2. {
  3. LPWSTRlpcwsStrDes=NULL;
  4. intlen=MultiByteToWideChar(CodePage,0,lpcszSrcStr,-1,NULL,0);
  5. lpcwsStrDes=newwchar_t[len+1];
  6. if(!lpcwsStrDes)
  7. returnNULL;
  8. memset(lpcwsStrDes,0,sizeof(wchar_t)*(len+1));
  9. len=MultiByteToWideChar(CodePage,0,lpcszSrcStr,-1,lpcwsStrDes,len);
  10. if(len)
  11. returnlpcwsStrDes;
  12. else
  13. {
  14. delete[]lpcwsStrDes;
  15. returnNULL;
  16. }
  17. }
  18. char*Coder::WCharToMByte(UINTCodePage,LPCWSTRlpcwszSrcStr)
  19. {
  20. char*lpszDesStr=NULL;
  21. intlen=WideCharToMultiByte(CodePage,0,lpcwszSrcStr,-1,NULL,0,NULL,NULL);
  22. lpszDesStr=newchar[len+1];
  23. memset(lpszDesStr,0,sizeof(char)*(len+1));
  24. if(!lpszDesStr)
  25. returnNULL;
  26. len=WideCharToMultiByte(CodePage,0,lpcwszSrcStr,-1,lpszDesStr,len,NULL,NULL);
  27. if(len)
  28. returnlpszDesStr;
  29. else
  30. {
  31. delete[]lpszDesStr;
  32. returnNULL;
  33. }
  34. }

c.LCMapString依賴於本地機器的字元轉換函數,尤其是中文編碼在轉換時要依賴於本地機器,直接利用上述a、b中敘述的函數會產生錯誤,例如直接從GB2312轉換到Big5,利用

MultiByteToWideChar函數將GB2312轉換到Unicode字元串,然後從Unicode字元串利用函數

WideCharToMultiByte轉換成Big5,將會發生錯誤,錯誤的結果如下圖所示:

因此中文編碼轉換時適當使用LCMapString函數,才能完成正確的轉換.例如:[cpp] view plaincopyprint?

  1. //簡體中文GB2312轉換成繁體中文BIG5
  2. char*Coder::GB2312ToBIG5(constchar*szGB2312Str)
  3. {
  4. LCIDlcid=MAKELCID(MAKELANGID(LANG_CHINESE,SUBLANG_CHINESE_SIMPLIFIED),SORT_CHINESE_PRC);
  5. intnLength=LCMapString(lcid,LCMAP_TRADITIONAL_CHINESE,szGB2312Str,-1,NULL,0);
  6. char*pBuffer=newchar[nLength+1];
  7. if(!pBuffer)
  8. returnNULL;
  9. LCMapString(lcid,LCMAP_TRADITIONAL_CHINESE,szGB2312Str,-1,pBuffer,nLength);
  10. pBuffer[nLength]=0;
  11. wchar_t*pUnicodeBuff=MByteToWChar(CP_GB2312,pBuffer);
  12. char*pBIG5Buff=WCharToMByte(CP_BIG5,pUnicodeBuff);
  13. delete[]pBuffer;
  14. delete[]pUnicodeBuff;
  15. returnpBIG5Buff;
  16. }

(5)編碼實現實現Coder類完成編碼轉換工作.Coder類的代碼清單如下:[cpp] view plaincopyprint?

  1. //Coder.h:interfacefortheCoderclass.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #if!defined(AFX_ENCODING_H__2AC955FB_9F8F_4871_9B77_C6C65730507F__INCLUDED_)
  5. #defineAFX_ENCODING_H__2AC955FB_9F8F_4871_9B77_C6C65730507F__INCLUDED_
  6. #if_MSC_VER>1000
  7. #pragmaonce
  8. #endif//_MSC_VER>1000
  9. //-----------------------------------------------------------------------------------------------
  10. //程序用途:實現GB2312、big5、GBK、Unicode、Unicodebigendian、UTF-8六種編碼的任意裝換
  11. //程序作者:湖北師範學院計算機科學與技術學院王定橋
  12. //核心演算法:根據不同編碼特點向其他編碼轉換
  13. //測試結果:在Windows7VC6.0環境下測試通過
  14. //製作時間:2012-04-24
  15. //代碼版權:代碼公開供學習交流使用歡迎指正錯誤改善演算法
  16. //-----------------------------------------------------------------------------------------------
  17. //Windows代碼頁
  18. typedefenumCodeType
  19. {
  20. CP_GB2312=936,
  21. CP_BIG5=950,
  22. CP_GBK=0//此處特殊處理CP_GBK僅作一標誌GBK代碼頁值尚未查得
  23. }CodePages;
  24. //txt文件編碼
  25. typedefenumTextCodeType
  26. {
  27. GB2312=0,
  28. BIG5=1,
  29. GBK=2,
  30. UTF8=3,
  31. UNICODE=4,
  32. UNICODEBIGENDIAN=5,
  33. DefaultCodeType=-1
  34. }TextCode;
  35. classCoder
  36. {
  37. public:
  38. Coder();
  39. virtual~Coder();
  40. public:
  41. //默認一次轉換位元組大小
  42. UINTPREDEFINEDSIZE;
  43. //指定轉換時默認一次轉換位元組大小
  44. voidSetDefaultConvertSize(UINTnCount);
  45. //編碼類型轉換為字元串
  46. CStringCodeTypeToString(TextCodetc);
  47. //文件轉到另一種文件
  48. BOOLFileToOtherFile(CStringfilesourcepath,CStringfilesavepath,TextCodetcTo,TextCodetcCur=DefaultCodeType);
  49. //Unicode和Unicodebigendian文件之間轉換
  50. BOOLUnicodeEndianFileConvert(CStringfilesourcepath,CStringfilesavepath,TextCodetcTo);
  51. //多位元組文件之間的轉換
  52. BOOLMBFileToMBFile(CStringfilesourcepath,CStringfilesavepath,TextCodetcTo,TextCodetcCur=DefaultCodeType);
  53. //Unicode和Unicodebigendian文件向多位元組文件轉換
  54. BOOLUnicodeFileToMBFile(CStringfilesourcepath,CStringfilesavepath,TextCodetcTo);
  55. //多位元組文件向Unicode和Unicodebigendian文件轉換
  56. BOOLMBFileToUnicodeFile(CStringfilesourcepath,CStringfilesavepath,TextCodetcTo,TextCodetcCur=DefaultCodeType);
  57. //獲取文件編碼類型
  58. TextCodeGetCodeType(CStringfilepath);
  59. //繁體中文BIG5轉換成簡體中文GB2312
  60. char*BIG5ToGB2312(constchar*szBIG5Str);
  61. //簡體中文GB2312轉換成繁體中文BIG5
  62. char*GB2312ToBIG5(constchar*szGB2312Str);
  63. //簡繁中文GBK編碼轉換成簡體中文GB2312
  64. char*GBKToGB2312(constchar*szGBkStr);
  65. //簡體中文GB2312編碼轉換成簡繁中文GBK
  66. char*GB2312ToGBK(constchar*szGB2312Str);
  67. //簡繁中文GBK轉換成繁體中文Big5
  68. char*GBKToBIG5(constchar*szGBKStr);
  69. //繁體中文BIG5轉換到簡繁中文GBK
  70. char*BIG5ToGBK(constchar*szBIG5Str);
  71. //寬字元串向多位元組字元串轉換
  72. char*WCharToMByte(UINTCodePage,LPCWSTRlpcwszSrcStr);
  73. //多位元組字元串向寬字元串轉換
  74. wchar_t*MByteToWChar(UINTCodePage,LPCSTRlpcszSrcStr);
  75. protected:
  76. //獲取編碼類型對應的代碼頁
  77. UINTGetCodePage(TextCodetccur);
  78. //多位元組向多位元組轉換
  79. char*MByteToMByte(UINTCodePageCur,UINTCodePageTo,constchar*szSrcStr);
  80. //Unicode和Unicodebigendian字元串之間的轉換
  81. voidUnicodeEndianConvert(LPWSTRlpwszstr);
  82. //文件頭常量位元組數組
  83. conststaticbyteUNICODEBOM[2];
  84. conststaticbyteUNICODEBEBOM[2];
  85. conststaticbyteUTF8BOM[3];
  86. };
  87. #endif//!defined(AFX_ENCODING_H__2AC955FB_9F8F_4871_9B77_C6C65730507F__INCLUDED_)

[cpp] view plaincopyprint?

  1. //Coder.cpp:implementationoftheCoderclass.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include"stdafx.h"
  5. #include"Coder.h"
  6. #include"Encoding.h"
  7. #ifdef_DEBUG
  8. #undefTHIS_FILE
  9. staticcharTHIS_FILE[]=__FILE__;
  10. #definenewDEBUG_NEW
  11. #endif
  12. //////////////////////////////////////////////////////////////////////
  13. //Construction/Destruction
  14. //////////////////////////////////////////////////////////////////////
  15. //初始化文件頭常量
  16. /*static*/constbyteCoder::UNICODEBOM[2]={0xFF,0xFE};
  17. /*static*/constbyteCoder::UNICODEBEBOM[2]={0xFE,0xFF};
  18. /*static*/constbyteCoder::UTF8BOM[3]={0xEF,0xBB,0xBF};
  19. Coder::Coder()
  20. {
  21. PREDEFINEDSIZE=2097152;//默認一次轉換位元組大小2M位元組
  22. }
  23. Coder::~Coder()
  24. {
  25. }
  26. //繁體中文BIG5轉換成簡體中文GB2312
  27. char*Coder::BIG5ToGB2312(constchar*szBIG5Str)
  28. {
  29. CStringmsg;
  30. LCIDlcid=MAKELCID(MAKELANGID(LANG_CHINESE,SUBLANG_CHINESE_SIMPLIFIED),SORT_CHINESE_PRC);
  31. wchar_t*szUnicodeBuff=MByteToWChar(CP_BIG5,szBIG5Str);
  32. char*szGB2312Buff=WCharToMByte(CP_GB2312,szUnicodeBuff);
  33. intnLength=LCMapString(lcid,LCMAP_SIMPLIFIED_CHINESE,szGB2312Buff,-1,NULL,0);
  34. char*pBuffer=newchar[nLength+1];
  35. if(!pBuffer)
  36. returnNULL;
  37. memset(pBuffer,0,sizeof(char)*(nLength+1));
  38. LCMapString(0x0804,LCMAP_SIMPLIFIED_CHINESE,szGB2312Buff,-1,pBuffer,nLength);
  39. delete[]szUnicodeBuff;
  40. delete[]szGB2312Buff;
  41. returnpBuffer;
  42. }
  43. //GB2312轉GBK
  44. char*Coder::GB2312ToGBK(constchar*szGB2312Str)
  45. {
  46. intnStrLen=strlen(szGB2312Str);
  47. if(!nStrLen)
  48. returnNULL;
  49. LCIDwLCID=MAKELCID(MAKELANGID(LANG_CHINESE,SUBLANG_CHINESE_SIMPLIFIED),SORT_CHINESE_PRC);
  50. intnReturn=LCMapString(wLCID,LCMAP_TRADITIONAL_CHINESE,szGB2312Str,nStrLen,NULL,0);
  51. if(!nReturn)
  52. returnNULL;
  53. char*pcBuf=newchar[nReturn+1];
  54. if(!pcBuf)
  55. returnNULL;
  56. memset(pcBuf,0,sizeof(char)*(nReturn+1));
  57. wLCID=MAKELCID(MAKELANGID(LANG_CHINESE,SUBLANG_CHINESE_SIMPLIFIED),SORT_CHINESE_PRC);
  58. LCMapString(wLCID,LCMAP_TRADITIONAL_CHINESE,szGB2312Str,nReturn,pcBuf,nReturn);
  59. returnpcBuf;
  60. }
  61. //GBK轉換成GB2312
  62. char*Coder::GBKToGB2312(constchar*szGBKStr)
  63. {
  64. intnStrLen=strlen(szGBKStr);
  65. if(!nStrLen)
  66. returnNULL;
  67. LCIDwLCID=MAKELCID(MAKELANGID(LANG_CHINESE,SUBLANG_CHINESE_SIMPLIFIED),SORT_CHINESE_BIG5);
  68. intnReturn=LCMapString(wLCID,LCMAP_SIMPLIFIED_CHINESE,szGBKStr,nStrLen,NULL,0);
  69. if(!nReturn)
  70. returnNULL;
  71. char*pcBuf=newchar[nReturn+1];
  72. memset(pcBuf,0,sizeof(char)*(nReturn+1));
  73. wLCID=MAKELCID(MAKELANGID(LANG_CHINESE,SUBLANG_CHINESE_SIMPLIFIED),SORT_CHINESE_BIG5);
  74. LCMapString(wLCID,LCMAP_SIMPLIFIED_CHINESE,szGBKStr,nReturn,pcBuf,nReturn);
  75. returnpcBuf;
  76. }
  77. //簡繁中文GBK轉換成繁體中文Big5
  78. char*Coder::GBKToBIG5(constchar*szGBKStr)
  79. {
  80. char*pTemp=NULL;
  81. char*pBuffer=NULL;
  82. pTemp=GBKToGB2312(szGBKStr);
  83. pBuffer=GB2312ToBIG5(pTemp);
  84. delete[]pTemp;
  85. returnpBuffer;
  86. }
  87. //繁體中文BIG5轉換到簡繁中文GBK
  88. char*Coder::BIG5ToGBK(constchar*szBIG5Str)
  89. {
  90. char*pTemp=NULL;
  91. char*pBuffer=NULL;
  92. pTemp=BIG5ToGB2312(szBIG5Str);
  93. pBuffer=GB2312ToGBK(pTemp);
  94. delete[]pTemp;
  95. returnpBuffer;
  96. }
  97. //簡體中文GB2312轉換成繁體中文BIG5
  98. char*Coder::GB2312ToBIG5(constchar*szGB2312Str)
  99. {
  100. LCIDlcid=MAKELCID(MAKELANGID(LANG_CHINESE,SUBLANG_CHINESE_SIMPLIFIED),SORT_CHINESE_PRC);
  101. intnLength=LCMapString(lcid,LCMAP_TRADITIONAL_CHINESE,szGB2312Str,-1,NULL,0);
  102. char*pBuffer=newchar[nLength+1];
  103. if(!pBuffer)
  104. returnNULL;
  105. LCMapString(lcid,LCMAP_TRADITIONAL_CHINESE,szGB2312Str,-1,pBuffer,nLength);
  106. pBuffer[nLength]=0;
  107. wchar_t*pUnicodeBuff=MByteToWChar(CP_GB2312,pBuffer);
  108. char*pBIG5Buff=WCharToMByte(CP_BIG5,pUnicodeBuff);
  109. delete[]pBuffer;
  110. delete[]pUnicodeBuff;
  111. returnpBIG5Buff;
  112. }
  113. //獲取文件編碼類型
  114. //Unicode編碼文件通過讀取文件頭判別
  115. //中文編碼通過統計文件編碼類別來判別判別次數最多為30次
  116. //中文編碼的判別存在誤差
  117. TextCodeCoder::GetCodeType(CStringfilepath)
  118. {
  119. CFilefile;
  120. bytebuf[3];//unsignedchar
  121. TextCodetctemp;
  122. if(file.Open(filepath,CFile::modeRead))
  123. {
  124. file.Read(buf,3);
  125. if(buf[0]==UTF8BOM[0]&&buf[1]==UTF8BOM[1]&&buf[2]==UTF8BOM[2])
  126. returnUTF8;
  127. else
  128. if(buf[0]==UNICODEBOM[0]&&buf[1]==UNICODEBOM[1])
  129. returnUNICODE;
  130. else
  131. if(buf[0]==UNICODEBEBOM[0]&&buf[1]==UNICODEBEBOM[1])
  132. returnUNICODEBIGENDIAN;
  133. else
  134. {
  135. inttime=30;
  136. while(file.Read(buf,2)&&time)
  137. {
  138. if((buf[0]>=176&&buf[0]<=247)&&(buf[1]>=160&&buf[1]<=254))
  139. tctemp=GB2312;
  140. else
  141. if((buf[0]>=129&&buf[0]<=255)&&((buf[1]>=64&&buf[1]<=126)||(buf[1]>=161&&buf[1]<=254)))
  142. tctemp=BIG5;
  143. else
  144. if((buf[0]>=129&&buf[0]<=254)&&(buf[1]>=64&&buf[1]<=254))
  145. tctemp=GBK;
  146. time--;
  147. file.Seek(100,CFile::current);//跳過一定位元組利於統計全文
  148. }
  149. returntctemp;
  150. }
  151. }
  152. else
  153. returnGB2312;
  154. }
  155. //多位元組文件轉換為UNICODE、UNICODEbigendian文件
  156. BOOLCoder::MBFileToUnicodeFile(CStringfilesourcepath,CStringfilesavepath,TextCodetcTo,TextCodetcCur)
  157. {
  158. TextCodecurtc;
  159. CFilefilesource,filesave;;
  160. char*pChSrc=NULL;
  161. char*pChTemp=NULL;
  162. wchar_t*pwChDes=NULL;
  163. DWORDfilelength,readlen,len;
  164. intbufferlen,strlength;
  165. UINTCodePage;
  166. //由於存在誤差允許用戶自定義轉換
  167. if(tcCur!=DefaultCodeType)
  168. curtc=tcCur;
  169. else
  170. curtc=GetCodeType(filesourcepath);
  171. if(curtc>UTF8||tcTo<UNICODE||curtc==tcTo)
  172. returnFALSE;
  173. //源文件打開失敗或者源文件無內容後者保存文件建立失敗均返迴轉換失敗
  174. if(!filesource.Open(filesourcepath,CFile::modeRead)||0==(filelength=filesource.GetLength()))
  175. returnFALSE;
  176. if(!filesave.Open(filesavepath,CFile::modeCreate|CFile::modeWrite))
  177. returnFALSE;
  178. //預分配內存分配失敗則轉換失敗
  179. if(filelength<PREDEFINEDSIZE)
  180. bufferlen=filelength;
  181. else
  182. bufferlen=PREDEFINEDSIZE;
  183. pChSrc=newchar[bufferlen+1];
  184. if(!pChSrc)
  185. returnFALSE;
  186. //根據當前文件類別指定轉換代碼頁
  187. switch(curtc)
  188. {
  189. caseGB2312:
  190. CodePage=CP_GB2312;
  191. break;
  192. caseGBK:
  193. CodePage=CP_GB2312;//特殊處理
  194. break;
  195. caseBIG5:
  196. CodePage=CP_BIG5;
  197. break;
  198. caseUTF8:
  199. CodePage=CP_UTF8;
  200. break;
  201. default:
  202. break;
  203. }
  204. //UTF8文件跳過文件
  205. if(UTF8==curtc)
  206. filesource.Seek(3*sizeof(byte),CFile::begin);
  207. //寫入文件頭
  208. if(UNICODEBIGENDIAN==tcTo)
  209. filesave.Write(&UNICODEBEBOM,2*sizeof(byte));
  210. else
  211. filesave.Write(&UNICODEBOM,2*sizeof(byte));
  212. //讀取文件分段轉換知道結束
  213. while(filelength>0)
  214. {
  215. memset(pChSrc,0,sizeof(char)*(bufferlen+1));
  216. if(filelength>PREDEFINEDSIZE)
  217. len=PREDEFINEDSIZE;
  218. else
  219. len=filelength;
  220. readlen=filesource.Read(pChSrc,len);
  221. if(!readlen)
  222. break;
  223. //GBK轉換為GB2312處理
  224. if(GBK==curtc)
  225. {
  226. pChTemp=pChSrc;
  227. pChSrc=GBKToGB2312(pChSrc);
  228. }
  229. pwChDes=MByteToWChar(CodePage,pChSrc);
  230. if(pwChDes)
  231. {
  232. if(UNICODEBIGENDIAN==tcTo)
  233. UnicodeEndianConvert(pwChDes);
  234. strlength=wcslen(pwChDes)*2;//這裡注意寫入文件的長度
  235. filesave.Write(pwChDes,strlength);
  236. filesave.Flush();
  237. filelength-=readlen;
  238. }
  239. else
  240. break;
  241. }
  242. delete[]pChSrc;
  243. delete[]pChTemp;
  244. delete[]pwChDes;
  245. returnTRUE;
  246. }
  247. //
  248. wchar_t*Coder::MByteToWChar(UINTCodePage,LPCSTRlpcszSrcStr)
  249. {
  250. LPWSTRlpcwsStrDes=NULL;
  251. intlen=MultiByteToWideChar(CodePage,0,lpcszSrcStr,-1,NULL,0);
  252. lpcwsStrDes=newwchar_t[len+1];
  253. if(!lpcwsStrDes)
  254. returnNULL;
  255. memset(lpcwsStrDes,0,sizeof(wchar_t)*(len+1));
  256. len=MultiByteToWideChar(CodePage,0,lpcszSrcStr,-1,lpcwsStrDes,len);
  257. if(len)
  258. returnlpcwsStrDes;
  259. else
  260. {
  261. delete[]lpcwsStrDes;
  262. returnNULL;
  263. }
  264. }
  265. char*Coder::WCharToMByte(UINTCodePage,LPCWSTRlpcwszSrcStr)
  266. {
  267. char*lpszDesStr=NULL;
  268. intlen=WideCharToMultiByte(CodePage,0,lpcwszSrcStr,-1,NULL,0,NULL,NULL);
  269. lpszDesStr=newchar[len+1];
  270. memset(lpszDesStr,0,sizeof(char)*(len+1));
  271. if(!lpszDesStr)
  272. returnNULL;
  273. len=WideCharToMultiByte(CodePage,0,lpcwszSrcStr,-1,lpszDesStr,len,NULL,NULL);
  274. if(len)
  275. returnlpszDesStr;
  276. else
  277. {
  278. delete[]lpszDesStr;
  279. returnNULL;
  280. }
  281. }
  282. //Unicode和Unicodebigendian之間位元組序的轉換
  283. voidCoder::UnicodeEndianConvert(LPWSTRlpwszstr)
  284. {
  285. wchar_twchtemp[2];
  286. longindex;
  287. intlen=wcslen(lpwszstr);
  288. if(!len)
  289. return;
  290. //交換高低位元組直到遇到結束符
  291. index=0;
  292. while(index<len)
  293. {
  294. wchtemp[0]=lpwszstr[index];
  295. wchtemp[1]=lpwszstr[index+1];
  296. unsignedcharhigh,low;
  297. high=(wchtemp[0]&0xFF00)>>8;
  298. low=wchtemp[0]&0x00FF;
  299. wchtemp[0]=(low<<8)|high;
  300. high=(wchtemp[1]&0xFF00)>>8;
  301. low=wchtemp[1]&0x00FF;
  302. wchtemp[1]=(low<<8)|high;
  303. lpwszstr[index]=wchtemp[0];
  304. lpwszstr[index+1]=wchtemp[1];
  305. index+=2;
  306. }
  307. }
  308. //Unicode和Unicodebigendian文件向多位元組文件轉換
  309. BOOLCoder::UnicodeFileToMBFile(CStringfilesourcepath,CStringfilesavepath,TextCodetcTo)
  310. {
  311. TextCodecurtc;
  312. CFilefilesource,filesave;;
  313. char*pChDes=NULL;
  314. char*pChTemp=NULL;
  315. wchar_t*pwChSrc=NULL;
  316. DWORDfilelength,readlen,len;
  317. intbufferlen,strlength;
  318. UINTCodePage;
  319. curtc=GetCodeType(filesourcepath);
  320. //文件轉換類型錯誤則轉換失敗
  321. if(curtc<=UTF8||tcTo>UTF8||curtc==tcTo)
  322. returnFALSE;
  323. //源文件打開失敗或者源文件無內容後者保存文件建立失敗均轉換失敗
  324. if(!filesource.Open(filesourcepath,CFile::modeRead)||0==(filelength=filesource.GetLength()))
  325. returnFALSE;
  326. if(!filesave.Open(filesavepath,CFile::modeCreate|CFile::modeWrite))
  327. returnFALSE;
  328. //預分配內存分配失敗則轉換失敗
  329. if(filelength<PREDEFINEDSIZE)
  330. bufferlen=filelength;
  331. else
  332. bufferlen=PREDEFINEDSIZE;
  333. pwChSrc=newwchar_t[(bufferlen/2)+1];
  334. if(!pwChSrc)
  335. returnFALSE;
  336. //預先決定代碼頁
  337. switch(tcTo)
  338. {
  339. caseGB2312:
  340. CodePage=CP_GB2312;
  341. break;
  342. caseGBK:
  343. CodePage=CP_GB2312;//特殊處理
  344. break;
  345. caseBIG5:
  346. CodePage=CP_GB2312;//特殊處理
  347. break;
  348. caseUTF8:
  349. CodePage=CP_UTF8;
  350. break;
  351. default:
  352. break;
  353. }
  354. filesource.Seek(sizeof(wchar_t),CFile::begin);
  355. while(filelength>0)
  356. {
  357. memset(pwChSrc,0,sizeof(wchar_t)*((bufferlen/2)+1));
  358. if(filelength>PREDEFINEDSIZE)
  359. len=PREDEFINEDSIZE;
  360. else
  361. len=filelength;
  362. readlen=filesource.Read(pwChSrc,len);
  363. if(!readlen)
  364. break;
  365. if(UNICODEBIGENDIAN==curtc)
  366. UnicodeEndianConvert(pwChSrc);
  367. pChDes=WCharToMByte(CodePage,pwChSrc);
  368. //GBK無法直接轉換BIG5直接轉換會產生錯誤二者均先轉到GB2312然後再轉到目的類型
  369. if(GBK==tcTo)
  370. {
  371. pChTemp=pChDes;
  372. pChDes=GB2312ToGBK(pChDes);
  373. }
  374. if(BIG5==tcTo)
  375. {
  376. pChTemp=pChDes;
  377. pChDes=GB2312ToBIG5(pChDes);
  378. }
  379. if(pChDes)
  380. {
  381. strlength=strlen(pChDes);
  382. filesave.Write(pChDes,strlength);
  383. filesave.Flush();
  384. filelength-=readlen;
  385. }
  386. else
  387. break;
  388. }
  389. delete[]pChDes;
  390. delete[]pChTemp;
  391. delete[]pwChSrc;
  392. returnTRUE;
  393. }
  394. //多位元組文件轉為多位元組文件
  395. //多位元組轉為多位元組時,一般先轉為UNICODE類型,再轉換到指定目的類型,實行兩次轉換
  396. BOOLCoder::MBFileToMBFile(CStringfilesourcepath,CStringfilesavepath,TextCodetcTo,TextCodetcCur)
  397. {
  398. BOOLbret=FALSE;
  399. TextCodecurtc;
  400. CFilefilesource,filesave;
  401. char*pChDes=NULL;
  402. char*pChSrc=NULL;
  403. DWORDfilelength,readlen,len;
  404. intbufferlen,strlength;
  405. UINTCodePageCur,CodePageTo;
  406. //由於存在誤差允許用戶自定義轉換
  407. if(DefaultCodeType!=tcCur)
  408. curtc=tcCur;
  409. else
  410. curtc=GetCodeType(filesourcepath);
  411. //轉換類型錯誤則返迴轉換失敗
  412. if(curtc>UTF8||tcTo>UTF8||curtc==tcTo)
  413. returnFALSE;
  414. //源文件打開失敗或者源文件無內容後者保存文件建立失敗均返迴轉換失敗
  415. if(!filesource.Open(filesourcepath,CFile::modeRead)||0==(filelength=filesource.GetLength()))
  416. returnFALSE;
  417. if(!filesave.Open(filesavepath,CFile::modeCreate|CFile::modeWrite))
  418. returnFALSE;
  419. //預分配內存分配失敗則轉換失敗
  420. if(filelength<PREDEFINEDSIZE)
  421. bufferlen=filelength;
  422. else
  423. bufferlen=PREDEFINEDSIZE;
  424. pChSrc=newchar[bufferlen+1];
  425. if(!pChSrc)
  426. returnFALSE;
  427. if(UTF8==curtc)
  428. filesource.Seek(3*sizeof(byte),CFile::begin);
  429. CodePageCur=GetCodePage(curtc);
  430. CodePageTo=GetCodePage(tcTo);
  431. while(filelength>0)
  432. {
  433. memset(pChSrc,0,sizeof(char)*(bufferlen+1));
  434. if(filelength>PREDEFINEDSIZE)
  435. len=PREDEFINEDSIZE;
  436. else
  437. len=filelength;
  438. readlen=filesource.Read(pChSrc,len);
  439. if(!readlen)
  440. break;
  441. pChDes=MByteToMByte(CodePageCur,CodePageTo,pChSrc);
  442. if(pChDes)
  443. {
  444. strlength=strlen(pChDes);
  445. filesave.Write(pChDes,strlength);
  446. filelength-=readlen;
  447. }
  448. else
  449. break;
  450. }
  451. delete[]pChSrc;
  452. delete[]pChDes;
  453. returnTRUE;
  454. }
  455. //Unicode和Unicodebigendian文件之間轉換
  456. BOOLCoder::UnicodeEndianFileConvert(CStringfilesourcepath,CStringfilesavepath,TextCodetcTo)
  457. {
  458. TextCodecurtc=GetCodeType(filesourcepath);
  459. if(curtc!=UNICODE&&curtc!=UNICODEBIGENDIAN)
  460. returnFALSE;
  461. if(curtc==tcTo)
  462. returnFALSE;
  463. CFilefilesource,filesave;;
  464. wchar_t*pwChDes;
  465. DWORDlength;
  466. if(!filesource.Open(filesourcepath,CFile::modeRead)||!filesave.Open(filesavepath,CFile::modeCreate|CFile::modeWrite))
  467. returnFALSE;
  468. length=filesource.GetLength();
  469. if(!length)
  470. returnFALSE;
  471. pwChDes=newwchar_t[(length/2)+1];
  472. if(!pwChDes)
  473. returnFALSE;
  474. memset(pwChDes,0,sizeof(wchar_t)*((length/2)+1));
  475. filesource.Read(pwChDes,length);
  476. UnicodeEndianConvert(pwChDes);
  477. length=wcslen(pwChDes)*2;
  478. if(UNICODE==tcTo)
  479. filesave.Write(&UNICODEBOM,2*sizeof(byte));
  480. else
  481. filesave.Write(&UNICODEBEBOM,2*sizeof(byte));
  482. filesave.Write(pwChDes,length);
  483. filesave.Flush();
  484. delete[]pwChDes;
  485. returnTRUE;
  486. }
  487. //文件轉到另一種文件
  488. //6種格式文件兩兩轉換共計30種轉換
  489. BOOLCoder::FileToOtherFile(CStringfilesourcepath,CStringfilesavepath,TextCodetcTo,TextCodetcCur)
  490. {
  491. TextCodecurtc;
  492. BOOLbret=FALSE;
  493. if(DefaultCodeType!=tcCur)
  494. curtc=tcCur;
  495. else
  496. curtc=GetCodeType(filesourcepath);
  497. if(curtc==tcTo)
  498. returnFALSE;
  499. //UNICODE和UNICODEbigendian文件之間轉換共2種
  500. if(curtc>=UNICODE&&tcTo>=UNICODE)
  501. bret=UnicodeEndianFileConvert(filesourcepath,filesavepath,tcTo);
  502. else
  503. //多位元組文件向UNICODE和UNICODEbigendian文件之間轉換共8種
  504. if(curtc<UNICODE&&tcTo>=UNICODE)
  505. bret=MBFileToUnicodeFile(filesourcepath,filesavepath,tcTo,curtc);
  506. else
  507. //UNICODE和UNICODEbigendian文件向多位元組文件轉換共8種
  508. if(curtc>=UNICODE&&tcTo<UNICODE)
  509. bret=UnicodeFileToMBFile(filesourcepath,filesavepath,tcTo);
  510. else
  511. //多位元組文件之間轉換共12種
  512. if(curtc<UNICODE&&tcTo<UNICODE)
  513. bret=MBFileToMBFile(filesourcepath,filesavepath,tcTo,curtc);
  514. returnbret;
  515. }
  516. //編碼類型轉換為字元串
  517. CStringCoder::CodeTypeToString(TextCodetc)
  518. {
  519. CStringstrtype;
  520. switch(tc)
  521. {
  522. caseGB2312:
  523. strtype=_T("GB2312");
  524. break;
  525. caseBIG5:
  526. strtype=_T("Big5");
  527. break;
  528. caseGBK:
  529. strtype=_T("GBK");
  530. break;
  531. caseUTF8:
  532. strtype=_T("UTF-8");
  533. break;
  534. caseUNICODE:
  535. strtype=_T("Unicode");
  536. break;
  537. caseUNICODEBIGENDIAN:
  538. strtype=_T("Unicodebigendian");
  539. break;
  540. }
  541. returnstrtype;
  542. }
  543. //多位元組向多位元組轉換
  544. char*Coder::MByteToMByte(UINTCodePageCur,UINTCodePageTo,constchar*szSrcStr)
  545. {
  546. char*pchDes=NULL;
  547. char*pchTemp=NULL;
  548. wchar_t*pwchtemp=NULL;
  549. //三種中文編碼之間轉換
  550. if(CodePageCur!=CP_UTF8&&CodePageTo!=CP_UTF8)
  551. {
  552. switch(CodePageCur)
  553. {
  554. caseCP_GB2312:
  555. {
  556. if(CP_BIG5==CodePageTo)
  557. pchDes=GB2312ToBIG5(szSrcStr);
  558. else
  559. pchDes=GB2312ToGBK(szSrcStr);
  560. break;
  561. }
  562. caseCP_BIG5:
  563. {
  564. if(CP_GB2312==CodePageTo)
  565. pchDes=BIG5ToGB2312(szSrcStr);
  566. else
  567. pchDes=BIG5ToGBK(szSrcStr);
  568. break;
  569. }
  570. caseCP_GBK:
  571. {
  572. if(CP_GB2312==CodePageTo)
  573. pchDes=GBKToGB2312(szSrcStr);
  574. else
  575. pchDes=GBKToBIG5(szSrcStr);
  576. break;
  577. }
  578. }
  579. }
  580. else
  581. {//從UTF-8轉到其他多位元組直接轉到GB2312其他形式用GB2312做中間形式
  582. if(CP_UTF8==CodePageCur)
  583. {
  584. pwchtemp=MByteToWChar(CodePageCur,szSrcStr);
  585. if(CP_GB2312==CodePageTo)
  586. {
  587. pchDes=WCharToMByte(CP_GB2312,pwchtemp);
  588. }
  589. else
  590. {
  591. pchTemp=WCharToMByte(CP_GB2312,pwchtemp);
  592. if(CP_GBK==CodePageTo)
  593. pchDes=GB2312ToGBK(pchTemp);
  594. else
  595. pchDes=GB2312ToBIG5(pchTemp);
  596. }
  597. }
  598. //從其他多位元組轉到UTF-8
  599. else
  600. {
  601. if(CP_GBK==CodePageCur)
  602. {
  603. pchTemp=GBKToGB2312(szSrcStr);
  604. pwchtemp=MByteToWChar(CP_GB2312,pchTemp);
  605. }
  606. else
  607. pwchtemp=MByteToWChar(CodePageCur,szSrcStr);
  608. pchDes=WCharToMByte(CodePageTo,pwchtemp);
  609. }
  610. }
  611. delete[]pchTemp;
  612. delete[]pwchtemp;
  613. returnpchDes;
  614. }
  615. //獲取編碼類型對應的代碼頁
  616. UINTCoder::GetCodePage(TextCodetccur)
  617. {
  618. UINTCodePage;
  619. switch(tccur)
  620. {
  621. caseGB2312:
  622. CodePage=CP_GB2312;
  623. break;
  624. caseBIG5:
  625. CodePage=CP_BIG5;
  626. break;
  627. caseGBK:
  628. CodePage=CP_GBK;
  629. break;
  630. caseUTF8:
  631. CodePage=CP_UTF8;
  632. break;
  633. caseUNICODEBIGENDIAN:
  634. caseUNICODE:
  635. break;
  636. }
  637. returnCodePage;
  638. }
  639. //指定轉換時默認一次轉換位元組大小
  640. voidCoder::SetDefaultConvertSize(UINTnCount)
  641. {
  642. if(nCount!=0)
  643. PREDEFINEDSIZE=nCount;
  644. }

3.運行效果 在win7 VC 6.0下測試六種編碼的轉換測試通過,30個方向的轉換如下圖所示:

測試程序運行效果如下圖所示:

GB2312轉換到GBK編碼效果如下圖所示:

UTF-8轉換到Big5編碼的效果如下圖所示:

本文代碼及轉碼程序下載 :http://download.csdn.net/user/ziyuanxiazai123

4.尚未解決的問題

(1)LCMapString函數的理解還不完全熟悉,其中參數偏多,理解需要一定基礎知識。

(2)為什麼記事本程序的轉碼後存在些亂碼,亂碼是正確的嗎?因為我的程序使用了中間過渡形式,因此沒有任何亂碼。

(3)是否有更簡單和清晰的方式實現編碼轉換,待進一步研究。


推薦閱讀:

簡繁轉換易錯字43例(下)
如何將星座的赤經和赤緯轉換為地球上的經度緯度.(最好寫的詳細點.)
時間轉換7
虛實轉換全在腰
梅竹再講;我編輯的[...顏色值..轉換器] 的應用和圖片編輯方法

TAG:編碼 | 中文 | 轉換 |