一网打尽中文编码转换——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(UINT CodePage,LPCSTR lpcszSrcStr)
  2. {
  3. LPWSTR lpcwsStrDes=NULL;
  4. int   len=MultiByteToWideChar(CodePage,0,lpcszSrcStr,-1,NULL,0);
  5. lpcwsStrDes=new wchar_t[len+1];
  6. if(!lpcwsStrDes)
  7. return NULL;
  8. memset(lpcwsStrDes,0,sizeof(wchar_t)*(len+1));
  9. len=MultiByteToWideChar(CodePage,0,lpcszSrcStr,-1,lpcwsStrDes,len);
  10. if(len)
  11. return lpcwsStrDes;
  12. else
  13. {
  14. delete[] lpcwsStrDes;
  15. return NULL;
  16. }
  17. }
  18. char* Coder::WCharToMByte(UINT CodePage,LPCWSTR lpcwszSrcStr)
  19. {
  20. char* lpszDesStr=NULL;
  21. int len=WideCharToMultiByte(CodePage,0,lpcwszSrcStr,-1,NULL,0,NULL,NULL);
  22. lpszDesStr=new char[len+1];
  23. memset(lpszDesStr,0,sizeof(char)*(len+1));
  24. if(!lpszDesStr)
  25. return NULL;
  26. len=WideCharToMultiByte(CodePage,0,lpcwszSrcStr,-1,lpszDesStr,len,NULL,NULL);
  27. if(len)
  28. return lpszDesStr;
  29. else
  30. {
  31. delete[] lpszDesStr;
  32. return NULL;
  33. }
  34. }
c.LCMapString
依赖于本地机器的字符转换函数,尤其是中文编码在转换时要依赖于本地机器,
直接利用上述a、b中叙述的函数会产生错误,例如直接从GB2312转换到Big5,利用
MultiByteToWideChar函数将GB2312转换到Unicode字符串,然后从Unicode字符串利用函数
WideCharToMultiByte转换成Big5,将会发生错误,错误的结果如下图所示:
因此中文编码转换时适当使用LCMapString函数,才能完成正确的转换.
例如:

测试程序运行效果如下图所示:


GB2312转换到GBK编码效果如下图所示:


UTF-8转换到Big5编码的效果如下图所示:


本文代码及转码程序下载 :http://download.csdn.net/user/ziyuanxiazai123

4.尚未解决的问题

(1)LCMapString函数的理解还不完全熟悉,其中参数偏多,理解需要一定基础知识。
(2)为什么记事本程序的转码后存在些乱码,乱码是正确的吗?因为我的程序使用了中间过渡形式,因此没有任何乱码。
(3)是否有更简单和清晰的方式实现编码转换,待进一步研究。
[cpp] view plaincopyprint?
  1. //简体中文 GB2312 转换成 繁体中文BIG5
  2. char* Coder::GB2312ToBIG5(const char* szGB2312Str)
  3. {
  4. LCID lcid = MAKELCID(MAKELANGID(LANG_CHINESE,SUBLANG_CHINESE_SIMPLIFIED),SORT_CHINESE_PRC);
  5. int nLength = LCMapString(lcid,LCMAP_TRADITIONAL_CHINESE,szGB2312Str,-1,NULL,0);
  6. char* pBuffer=new char[nLength+1];
  7. if(!pBuffer)
  8. return NULL;
  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. return pBIG5Buff;
  16. }
(5)编码实现
实现Coder类完成编码转换工作.
Coder类的代码清单如下:
[cpp] view plaincopyprint?
  1. // Coder.h: interface for the Coder class.
  2. //
  3. //
  4. #if !defined(AFX_ENCODING_H__2AC955FB_9F8F_4871_9B77_C6C65730507F__INCLUDED_)
  5. #define AFX_ENCODING_H__2AC955FB_9F8F_4871_9B77_C6C65730507F__INCLUDED_
  6. #if _MSC_VER > 1000
  7. #pragma once
  8. #endif // _MSC_VER > 1000
  9. //-----------------------------------------------------------------------------------------------
  10. //程序用途:实现GB2312、big5、GBK、Unicode、Unicode big endian、UTF-8六种编码的任意装换
  11. //程序作者:湖北师范学院计算机科学与技术学院  王定桥
  12. //核心算法:根据不同编码特点向其他编码转换
  13. //测试结果:在Windows7 VC6.0环境下测试通过
  14. //制作时间:2012-04-24
  15. //代码版权:代码公开供学习交流使用  欢迎指正错误  改善算法
  16. //-----------------------------------------------------------------------------------------------
  17. //Windows代码页
  18. typedef enum CodeType
  19. {
  20. CP_GB2312=936,
  21. CP_BIG5=950,
  22. CP_GBK=0
  23. }CodePages;
  24. //txt文件编码
  25. typedef enum TextCodeType
  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. class Coder
  36. {
  37. public:
  38. Coder();
  39. virtual ~Coder();
  40. public:
  41. //默认一次转换字节大小
  42. UINT  PREDEFINEDSIZE;
  43. //指定转换时默认一次转换字节大小
  44. void SetDefaultConvertSize(UINT nCount);
  45. //编码类型转换为字符串
  46. CString  CodeTypeToString(TextCode tc);
  47. //文件转到另一种文件
  48. BOOL     FileToOtherFile(CString filesourcepath, CString filesavepath,TextCode tcTo,TextCode  tcCur=DefaultCodeType);
  49. //Unicode 和Unicode big endian文件之间转换
  50. BOOL     UnicodeEndianFileConvert(CString filesourcepath, CString filesavepath,TextCode tcTo);
  51. //多字节文件之间的转换
  52. BOOL     MBFileToMBFile(CString filesourcepath, CString filesavepath,TextCode tcTo,TextCode  tcCur=DefaultCodeType);
  53. //Unicode和Unicode big endian文件向多字节文件转换
  54. BOOL     UnicodeFileToMBFile(CString filesourcepath, CString filesavepath,TextCode tcTo);
  55. //多字节文件向Unicode和Unicode big endian文件转换
  56. BOOL     MBFileToUnicodeFile(CString filesourcepath,CString filesavepath,TextCode tcTo,TextCode  tcCur=DefaultCodeType);
  57. //获取文件编码类型
  58. TextCode GetCodeType(CString filepath);
  59. //繁体中文BIG5 转换成 简体中文 GB2312
  60. char* BIG5ToGB2312(const char* szBIG5Str);
  61. //简体中文 GB2312 转换成 繁体中文BIG5
  62. char* GB2312ToBIG5(const char* szGB2312Str);
  63. //简繁中文GBK编码转换成简体中文GB2312
  64. char* GBKToGB2312(const char *szGBkStr);
  65. //简体中文GB2312编码转换成简繁中文GBK
  66. char*    GB2312ToGBK(const char *szGB2312Str);
  67. //简繁中文GBK转换成繁体中文Big5
  68. char*     GBKToBIG5(const char *szGBKStr);
  69. //繁体中文BIG5转换到简繁中文GBK
  70. char*     BIG5ToGBK(const char *szBIG5Str);
  71. //宽字符串向多字节字符串转换
  72. char*     WCharToMByte(UINT CodePage,LPCWSTR lpcwszSrcStr);
  73. //多字节字符串向宽字符串转换
  74. wchar_t*  MByteToWChar(UINT CodePage,LPCSTR lpcszSrcStr);
  75. protected:
  76. //获取编码类型对应的代码页
  77. UINT GetCodePage(TextCode tccur);
  78. //多字节向多字节转换
  79. char*  MByteToMByte(UINT CodePageCur,UINT CodePageTo,const char* szSrcStr);
  80. //Unicode和Unicode big endian字符串之间的转换
  81. void   UnicodeEndianConvert(LPWSTR  lpwszstr);
  82. //文件头常量字节数组
  83. const  static   byte UNICODEBOM[2];
  84. const  static   byte UNICODEBEBOM[2];
  85. const  static   byte UTF8BOM[3];
  86. };
  87. #endif // !defined(AFX_ENCODING_H__2AC955FB_9F8F_4871_9B77_C6C65730507F__INCLUDED_)
[cpp] view plaincopyprint?
  1. // Coder.cpp: implementation of the Coder class.
  2. //
  3. //
  4. #include "stdafx.h"
  5. #include "Coder.h"
  6. #include "Encoding.h"
  7. #ifdef _DEBUG
  8. #undef THIS_FILE
  9. static char THIS_FILE[]=__FILE__;
  10. #define new DEBUG_NEW
  11. #endif
  12. //
  13. // Construction/Destruction
  14. //
  15. //初始化文件头常量
  16. /*static*/ const     byte Coder::UNICODEBOM[2]={0xFF,0xFE};
  17. /*static*/ const     byte Coder::UNICODEBEBOM[2]={0xFE,0xFF};
  18. /*static*/ const     byte Coder::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(const char* szBIG5Str)
  28. {
  29. CString msg;
  30. LCID lcid = 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. int nLength = LCMapString(lcid,LCMAP_SIMPLIFIED_CHINESE, szGB2312Buff,-1,NULL,0);
  34. char* pBuffer = new char[nLength + 1];
  35. if(!pBuffer)
  36. return NULL;
  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. return pBuffer;
  42. }
  43. // GB2312 转 GBK
  44. char* Coder::GB2312ToGBK(const char *szGB2312Str)
  45. {
  46. int nStrLen = strlen(szGB2312Str);
  47. if(!nStrLen)
  48. return NULL;
  49. LCID wLCID = MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_CHINESE_PRC);
  50. int nReturn = LCMapString(wLCID, LCMAP_TRADITIONAL_CHINESE, szGB2312Str, nStrLen, NULL, 0);
  51. if(!nReturn)
  52. return NULL;
  53. char *pcBuf = new char[nReturn + 1];
  54. if(!pcBuf)
  55. return NULL;
  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. return pcBuf;
  60. }
  61. // GBK 转换成 GB2312
  62. char* Coder::GBKToGB2312(const char *szGBKStr)
  63. {
  64. int nStrLen = strlen(szGBKStr);
  65. if(!nStrLen)
  66. return NULL;
  67. LCID wLCID = MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_CHINESE_BIG5);
  68. int nReturn = LCMapString(wLCID, LCMAP_SIMPLIFIED_CHINESE, szGBKStr, nStrLen, NULL, 0);
  69. if(!nReturn)
  70. return NULL;
  71. char *pcBuf = new char[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. return pcBuf;
  76. }
  77. //简繁中文GBK转换成繁体中文Big5
  78. char*   Coder::GBKToBIG5(const char *szGBKStr)
  79. {
  80. char *pTemp=NULL;
  81. char *pBuffer=NULL;
  82. pTemp=GBKToGB2312(szGBKStr);
  83. pBuffer=GB2312ToBIG5(pTemp);
  84. delete[] pTemp;
  85. return pBuffer;
  86. }
  87. //繁体中文BIG5转换到简繁中文GBK
  88. char*   Coder::BIG5ToGBK(const char *szBIG5Str)
  89. {
  90. char *pTemp=NULL;
  91. char *pBuffer=NULL;
  92. pTemp=BIG5ToGB2312(szBIG5Str);
  93. pBuffer=GB2312ToGBK(pTemp);
  94. delete[] pTemp;
  95. return pBuffer;
  96. }
  97. //简体中文 GB2312 转换成 繁体中文BIG5
  98. char* Coder::GB2312ToBIG5(const char* szGB2312Str)
  99. {
  100. LCID lcid = MAKELCID(MAKELANGID(LANG_CHINESE,SUBLANG_CHINESE_SIMPLIFIED),SORT_CHINESE_PRC);
  101. int nLength = LCMapString(lcid,LCMAP_TRADITIONAL_CHINESE,szGB2312Str,-1,NULL,0);
  102. char* pBuffer=new char[nLength+1];
  103. if(!pBuffer)
  104. return NULL;
  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. return pBIG5Buff;
  112. }
  113. //获取文件编码类型
  114. //Unicode编码文件通过读取文件头判别
  115. //中文编码通过统计文件编码类别来判别  判别次数最多为30次
  116. //中文编码的判别存在误差
  117. TextCode Coder::GetCodeType(CString filepath)
  118. {
  119. CFile file;
  120. byte  buf[3];//unsigned char
  121. TextCode tctemp;
  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. return UTF8;
  127. else
  128. if(buf[0]==UNICODEBOM[0] &&buf[1]==UNICODEBOM[1] )
  129. return UNICODE ;
  130. else
  131. if(buf[0]==UNICODEBEBOM[0] &&buf[1]==UNICODEBEBOM[1] )
  132. return UNICODEBIGENDIAN;
  133. else
  134. {
  135. int time=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. return tctemp;
  150. }
  151. }
  152. else
  153. return GB2312;
  154. }
  155. //多字节文件转换为UNICODE、UNICODE big endian文件
  156. BOOL Coder::MBFileToUnicodeFile(CString filesourcepath, CString filesavepath,TextCode tcTo,TextCode tcCur)
  157. {
  158. TextCode curtc;
  159. CFile filesource,filesave;;
  160. char     *pChSrc=NULL;
  161. char     *pChTemp=NULL;
  162. wchar_t  *pwChDes=NULL;
  163. DWORD  filelength,readlen,len;
  164. int    bufferlen,strlength;
  165. UINT CodePage;
  166. //由于存在误差  允许用户自定义转换
  167. if(tcCur!=DefaultCodeType)
  168. curtc=tcCur;
  169. else
  170. curtc=GetCodeType(filesourcepath);
  171. if(curtc>UTF8 || tcTo< UNICODE || curtc==tcTo)
  172. return FALSE;
  173. //源文件打开失败或者源文件无内容 后者保存文件建立失败   均返回转换失败
  174. if(!filesource.Open(filesourcepath,CFile::modeRead) || 0==(filelength=filesource.GetLength()))
  175. return FALSE;
  176. if( !filesave.Open(filesavepath,CFile::modeCreate|CFile::modeWrite))
  177. return FALSE;
  178. //预分配内存  分配失败则转换失败
  179. if(filelength<PREDEFINEDSIZE)
  180. bufferlen=filelength;
  181. else
  182. bufferlen=PREDEFINEDSIZE;
  183. pChSrc=new char[bufferlen+1];
  184. if(!pChSrc)
  185. return FALSE;
  186. //根据当前文件类别指定转换代码页
  187. switch(curtc)
  188. {
  189. case GB2312:
  190. CodePage=CP_GB2312;
  191. break;
  192. case GBK:
  193. CodePage=CP_GB2312;//特殊处理
  194. break;
  195. case BIG5:
  196. CodePage=CP_BIG5;
  197. break;
  198. case UTF8:
  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. return TRUE;
  246. }
  247. //
  248. wchar_t* Coder::MByteToWChar(UINT CodePage,LPCSTR lpcszSrcStr)
  249. {
  250. LPWSTR lpcwsStrDes=NULL;
  251. int   len=MultiByteToWideChar(CodePage,0,lpcszSrcStr,-1,NULL,0);
  252. lpcwsStrDes=new wchar_t[len+1];
  253. if(!lpcwsStrDes)
  254. return NULL;
  255. memset(lpcwsStrDes,0,sizeof(wchar_t)*(len+1));
  256. len=MultiByteToWideChar(CodePage,0,lpcszSrcStr,-1,lpcwsStrDes,len);
  257. if(len)
  258. return lpcwsStrDes;
  259. else
  260. {
  261. delete[] lpcwsStrDes;
  262. return NULL;
  263. }
  264. }
  265. char* Coder::WCharToMByte(UINT CodePage,LPCWSTR lpcwszSrcStr)
  266. {
  267. char* lpszDesStr=NULL;
  268. int len=WideCharToMultiByte(CodePage,0,lpcwszSrcStr,-1,NULL,0,NULL,NULL);
  269. lpszDesStr=new char[len+1];
  270. memset(lpszDesStr,0,sizeof(char)*(len+1));
  271. if(!lpszDesStr)
  272. return NULL;
  273. len=WideCharToMultiByte(CodePage,0,lpcwszSrcStr,-1,lpszDesStr,len,NULL,NULL);
  274. if(len)
  275. return lpszDesStr;
  276. else
  277. {
  278. delete[] lpszDesStr;
  279. return NULL;
  280. }
  281. }
  282. //Unicode 和Unicode big endian之间字节序的转换
  283. void Coder::UnicodeEndianConvert(LPWSTR lpwszstr)
  284. {
  285. wchar_t  wchtemp[2];
  286. long     index;
  287. int len=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. unsigned char high, 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和Unicode big endian文件向多字节文件转换
  309. BOOL Coder::UnicodeFileToMBFile(CString filesourcepath, CString filesavepath,TextCode tcTo)
  310. {
  311. TextCode curtc;
  312. CFile filesource,filesave;;
  313. char    *pChDes=NULL;
  314. char    *pChTemp=NULL;
  315. wchar_t *pwChSrc=NULL;
  316. DWORD  filelength,readlen,len;
  317. int    bufferlen,strlength;
  318. UINT CodePage;
  319. curtc=GetCodeType(filesourcepath);
  320. //文件转换类型错误 则转换失败
  321. if(curtc<=UTF8 ||  tcTo>UTF8 || curtc==tcTo)
  322. return FALSE;
  323. //源文件打开失败或者源文件无内容 后者保存文件建立失败   均转换失败
  324. if(!filesource.Open(filesourcepath,CFile::modeRead) || 0==(filelength=filesource.GetLength()))
  325. return FALSE;
  326. if( !filesave.Open(filesavepath,CFile::modeCreate|CFile::modeWrite))
  327. return FALSE;
  328. //预分配内存  分配失败则转换失败
  329. if(filelength<PREDEFINEDSIZE)
  330. bufferlen=filelength;
  331. else
  332. bufferlen=PREDEFINEDSIZE;
  333. pwChSrc=new wchar_t[(bufferlen/2)+1];
  334. if(!pwChSrc)
  335. return FALSE;
  336. //预先决定代码页
  337. switch(tcTo)
  338. {
  339. case GB2312:
  340. CodePage=CP_GB2312;
  341. break;
  342. case GBK:
  343. CodePage=CP_GB2312;//特殊处理
  344. break;
  345. case BIG5:
  346. CodePage=CP_GB2312;//特殊处理
  347. break;
  348. case UTF8:
  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. return TRUE;
  393. }
  394. //多字节文件转为多字节文件
  395. //多字节转为多字节时,一般先转为UNICODE类型,再转换到指定目的类型,实行两次转换
  396. BOOL Coder::MBFileToMBFile(CString filesourcepath, CString filesavepath,TextCode tcTo,TextCode  tcCur)
  397. {
  398. BOOL bret=FALSE;
  399. TextCode curtc;
  400. CFile filesource,filesave;
  401. char    *pChDes=NULL;
  402. char    *pChSrc=NULL;
  403. DWORD  filelength,readlen,len;
  404. int    bufferlen,strlength;
  405. UINT   CodePageCur,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. return FALSE;
  414. //源文件打开失败或者源文件无内容 后者保存文件建立失败   均返回转换失败
  415. if(!filesource.Open(filesourcepath,CFile::modeRead) || 0==(filelength=filesource.GetLength()))
  416. return FALSE;
  417. if( !filesave.Open(filesavepath,CFile::modeCreate|CFile::modeWrite))
  418. return FALSE;
  419. //预分配内存  分配失败则转换失败
  420. if(filelength<PREDEFINEDSIZE)
  421. bufferlen=filelength;
  422. else
  423. bufferlen=PREDEFINEDSIZE;
  424. pChSrc=new char[bufferlen+1];
  425. if(!pChSrc)
  426. return FALSE;
  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. return TRUE;
  454. }
  455. //Unicode 和Unicode big endian文件之间转换
  456. BOOL Coder::UnicodeEndianFileConvert(CString filesourcepath, CString filesavepath,TextCode tcTo)
  457. {
  458. TextCode curtc=GetCodeType(filesourcepath);
  459. if(curtc!=UNICODE && curtc!=UNICODEBIGENDIAN)
  460. return FALSE;
  461. if(curtc==tcTo)
  462. return FALSE;
  463. CFile filesource,filesave;;
  464. wchar_t *pwChDes;
  465. DWORD length;
  466. if(!filesource.Open(filesourcepath,CFile::modeRead) || !filesave.Open(filesavepath,CFile::modeCreate|CFile::modeWrite))
  467. return FALSE;
  468. length=filesource.GetLength();
  469. if(!length)
  470. return FALSE;
  471. pwChDes=new wchar_t[(length/2)+1];
  472. if(!pwChDes)
  473. return FALSE;
  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. return TRUE;
  486. }
  487. //文件转到另一种文件
  488. //6种格式文件两两转换  共计30种转换
  489. BOOL Coder::FileToOtherFile(CString filesourcepath, CString filesavepath, TextCode tcTo,TextCode  tcCur)
  490. {
  491. TextCode curtc;
  492. BOOL bret=FALSE;
  493. if(DefaultCodeType!=tcCur)
  494. curtc=tcCur;
  495. else
  496. curtc=GetCodeType(filesourcepath);
  497. if(curtc==tcTo)
  498. return FALSE;
  499. //UNICODE和UNICODE big endian文件之间转换 共2种
  500. if(curtc>=UNICODE&& tcTo>=UNICODE)
  501. bret=UnicodeEndianFileConvert(filesourcepath,filesavepath,tcTo);
  502. else
  503. //多字节文件向 UNICODE和UNICODE big endian文件之间转换 共8种
  504. if(curtc<UNICODE && tcTo>=UNICODE)
  505. bret=MBFileToUnicodeFile(filesourcepath,filesavepath,tcTo,curtc);
  506. else
  507. //UNICODE和UNICODE big endian文件向多字节文件转换 共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. return bret;
  515. }
  516. //编码类型转换为字符串
  517. CString Coder::CodeTypeToString(TextCode tc)
  518. {
  519. CString strtype;
  520. switch(tc)
  521. {
  522. case GB2312:
  523. strtype=_T("GB2312");
  524. break;
  525. case BIG5:
  526. strtype=_T("Big5");
  527. break;
  528. case GBK:
  529. strtype=_T("GBK");
  530. break;
  531. case UTF8:
  532. strtype=_T("UTF-8");
  533. break;
  534. case UNICODE:
  535. strtype=_T("Unicode");
  536. break;
  537. case UNICODEBIGENDIAN:
  538. strtype=_T("Unicode big endian");
  539. break;
  540. }
  541. return strtype;
  542. }
  543. //多字节向多字节转换
  544. char* Coder::MByteToMByte(UINT CodePageCur, UINT CodePageTo, const char* 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. case CP_GB2312:
  555. {
  556. if(CP_BIG5==CodePageTo)
  557. pchDes=GB2312ToBIG5(szSrcStr);
  558. else
  559. pchDes=GB2312ToGBK(szSrcStr);
  560. break;
  561. }
  562. case CP_BIG5:
  563. {
  564. if(CP_GB2312==CodePageTo)
  565. pchDes=BIG5ToGB2312(szSrcStr);
  566. else
  567. pchDes=BIG5ToGBK(szSrcStr);
  568. break;
  569. }
  570. case CP_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. return pchDes;
  614. }
  615. //获取编码类型对应的代码页
  616. UINT Coder::GetCodePage(TextCode tccur)
  617. {
  618. UINT CodePage;
  619. switch(tccur)
  620. {
  621. case GB2312:
  622. CodePage=CP_GB2312;
  623. break;
  624. case BIG5:
  625. CodePage=CP_BIG5;
  626. break;
  627. case GBK:
  628. CodePage=CP_GBK;
  629. break;
  630. case UTF8:
  631. CodePage=CP_UTF8;
  632. break;
  633. case UNICODEBIGENDIAN:
  634. case UNICODE:
  635. break;
  636. }
  637. return CodePage;
  638. }
  639. //指定转换时默认一次转换字节大小
  640. void Coder::SetDefaultConvertSize(UINT nCount)
  641. {
  642. if(nCount!=0)
  643. PREDEFINEDSIZE=nCount;
  644. }
3.运行效果                                                                                   
在win7 VC 6.0下测试六种编码的转换测试通过,30个方向的转换如下图所示:

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

  1. linux 文件格式latin1,Linux下查看文件编码,文件编码格式转换和文件名编码

    如果你需要在中操作windows下的文件,那么你可能会经常遇到文件编码转换的问题.Windows中默认的文件格式是GBK(gb2312),而Linux一般都是UTF-8.下面介绍一下,在Linux中如 ...

  2. base64转html文件,图片转换成Base64编码集成到html文件

    首先为什么要这么做?  原因很简单这样可以减少与服务器的请求,当然对于一些浏览器并不支持,如IE8.通常用在手机版网站中,具体转化方法如下: 1.在线打开Base64的编码器将图片编码成Base64 ...

  3. 设计一个灯光控制逻辑电路. 要求红、绿、黄三种颜色的灯在时钟信号的作用下按表P6.30规定的顺序转换状态

    题目: 设计一个灯光控制逻辑电路. 要求红.绿.黄三种颜色的灯在时钟信号的作用下按表P6.30规定的顺序转换状态. 表中的1表示"亮", 0表示"灭". 要求电 ...

  4. 在C#中,如何将一种编码的字符串转换成另外一种编码。

    当向服务器发送请求,然后获得返回的JSON的时候,字符串的编码可能不是我们想要的.比如返回的如果是GB2132,在C#里可能会是乱码.这时候,我们需要转码,比如把GB2132转成UTF-8. 下面函数 ...

  5. windows四种编码方式

    简单介绍一下这四种编码方式: ANSI:系统预设的标准文字储存格式.ANSI是American National Standards Institute的缩写.它成立于1918年,是一个自愿性的组织, ...

  6. Redis源码-String:Redis String命令、Redis String存储原理、Redis String三种编码类型、Redis字符串SDS源码解析、Redis String应用场景

    Redis源码-String:Redis String命令.Redis String存储原理.Redis String三种编码类型.Redis字符串SDS源码解析.Redis String应用场景 R ...

  7. html中转换utf8编码,如何将html网页utf-8编码转换到utf-8编码互转换

    HTML网页是有编码的,在head区域内的这句话是告诉浏览器,该网页采用的是utf-8编码,也就是简体中文编码.当文章/网页中包含繁体中文.日文.韩文时,这些内容可能无法被正确编码. UTF-8是UT ...

  8. 单片机中UTF-8如何转换得到GBK编码

    概述 我们在单片机开发中常会遇到需要将UTF-8转换为GBK编码的需求. 在我们了解各种编码格式的情况下可知, UFT-8不能直接转成GBK,需中转成unicode再转换为gbk.而unicode和g ...

  9. SQL语句行列转换两种方法 case ...when 和pivot函数应用

    2019独角兽企业重金招聘Python工程师标准>>> SQL语句行列转换两种方法 case ...when 和pivot函数应用SQL语句行列转换两种方法 case ...when ...

最新文章

  1. 印度资深数字货币研究员::我为什么选择BCH?
  2. Async/Await替代Promise的6个理由
  3. java学习(40):成员实例的定义和访问
  4. 程序发出的广播其他程序收不到_RabbitMQ 如何实现对同一个应用的多个节点进行广播...
  5. 海龟交易法则04_像海龟一样思考
  6. (转)Managed DirectX +C# 开发(入门篇)(三)
  7. 【代码审计】YUNUCMS_v1.0.6 后台代码执行漏洞分析
  8. Win11改Win10右键菜单
  9. ABP文档 - 通知系统
  10. 简单的交换机下设备连接,路由器互通
  11. 微信小程序毕业论文题目_SSM项目考勤签到管理系统+后台管理系统
  12. linux桌面鼠标可动 但点其他,电脑鼠标能动但点不了的两种解决方法
  13. 购买计算机如何选择CPU,怎么选购笔记本电脑CPU 选购笔记本电脑CPU方法【详解】...
  14. java group布局_Java的swing.GroupLayout布局管理器的使用方法和实例
  15. elementui 走马灯图片自适应
  16. GhostXP_SP3 电脑公司特别版 v2011.08
  17. Linux 常见指令及权限、OS(操作系统)基本概念
  18. amp;quot;等java转义
  19. 在VB中用PictureBox控件实现特殊符号工具栏
  20. 让GAN再次伟大!拖一拖关键点效果让人惊艳,汤晓鸥弟子的DragGAN爆火!

热门文章

  1. java weka 聚类_简单开源数据挖掘工具weka进行文本聚类
  2. python图形模块_使用Python图形模块:有没有办法将当前窗口保存为图像?
  3. c语言 有趣的代码,分享一段有趣的小代码
  4. 【牛客 - 317D】小a与黄金街道(数论,tricks)
  5. 详解停车位检测论文:Attentional Graph Neural Network for Parking-slot Detection
  6. 2.Explore Your Data
  7. 函授本科统考计算机考试时间,函授2006级计算机、机电本科第一学期考试时间安排.doc...
  8. windowsthinpc虚拟内存_windows thin pc如何开启windows功能
  9. 词法分析器c语言带注释,C语言词法分析器内容说明注释完整可运行代码.doc-资源下载在线文库www.lddoc.cn...
  10. 鸿蒙系统能否推广,鸿蒙系统凭实力占市场,无需通过禁止安卓系统来推广