`
xpp02
  • 浏览: 1014634 次
社区版块
存档分类
最新评论

一网打尽中文编码转换---6种编码30个方向的转换

 
阅读更多
一网打尽中文编码转换——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。
以上两个函数可以完成大部分的字符串转换,可以将其封装成多字节和宽字节之间的转换函数:

  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函数,才能完成正确的转换.
例如:

  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类的代码清单如下:
  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
  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_)
  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)是否有更简单和清晰的方式实现编码转换,待进一步研究。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics