目前,大陆地区常见的中文编码有以下三种。
GB2312
GB2312(1980年)一共收录了7445个字符,包括6763个汉字和682个其它符号。汉字区的内码范围高字节从B0-F7,低字节从A1-FE,占用的码位是72*94=6768。其中有5个空位是D7FA-D7FE。在windows中的代码页是CP936。
GBK
GBK最初是由微软对GB2312的扩展,也就是CP936字码表 (Code Page 936)的扩展。最初出现于Windows 95简体中文版中,由于Windows产品的流行和在大陆广泛被使用,*国家有关部门将其作为技术规范。注意GBK并非国家正式标准,只是国家技术监督局标准化司、电子工业部科技与质量监督司发布的“技术规范指导性文件”。GBK字集是简繁字集,包括了GB字集、BIG5字集和一些符号,共包括21003个字符。
GBK作为对GB2312的扩展,在现在的windows系统中仍然使用代码页CP936表示,但是同样的936的代码页跟一开始的936的代码页只支持GB2312编码不同,现在的936代码页支持GBK的编码,GBK同时也向下兼容GB2312编码。
GB18030
2000年的GB18030是取代GBK1.0的正式国家标准。该标准收录了27484个汉字,收录了藏文、蒙文、*文等主要的少数民族文字。现在的PC平台必须支持GB18030,对嵌入式产品暂不作要求。所以手机、MP3一般只支持GB2312。 GB18030在windows中的代码页是CP54936。
1.简体中文和繁体中文的转换
内码一般是指缺省代码页指定的编码,缺省代码页是默认用来解释字符的编码。简体中文windows系统缺省代码页是GBK。
ANSI编码:即所有在ASCII基础上扩充的字符编码的统称。在英文操作系统中ANSI是ASCII编码,繁体中文系统中ANSI是Big5编码,日文系统中ANSI是Shift_JIS编码,简体中文系统有点特殊,比如:editplus或记事本的默认编码为ANSI,但具体ANSI代表的是gbk还是gb2312还是gb18030,由这些编辑器根据码流去识别。window下很多文本编辑器都没有强行采用某种特定的编码,统一使用系统编码,所以中文win系统中ANSI就是GBK。
GBK字符集包括了简体字符集、繁体字符集以及一些中文符号,当然同一汉字简繁字体在GBK下对应两种不同编码方式。可以,在ANSI编码下的简繁转化实质是在GBK编码表内的映射转化。
window头文件中提供了LCMapString function可以实现映射功能,程序如下
/* *作者:侯凯 *说明:中文简繁的相互转化 *日期:2013-6-18 */ #include <Windows.h> #include <iostream> using namespace std; //中国->中國 char* Simple2Tra(char* szBuf) { if(!strcmp(szBuf, "")) return NULL; int nReturn = LCMapString(LOCALE_SYSTEM_DEFAULT, LCMAP_TRADITIONAL_CHINESE, szBuf, -1, NULL, 0); char *pcBuf = new char[nReturn]; LCMapString(LOCALE_SYSTEM_DEFAULT, LCMAP_TRADITIONAL_CHINESE, szBuf, -1, pcBuf, nReturn); return pcBuf; } //中國->中国 char* Tra2Simple(char* szBuf) { if(!strcmp(szBuf, "")) return NULL; int nReturn = LCMapString(LOCALE_SYSTEM_DEFAULT, LCMAP_SIMPLIFIED_CHINESE, szBuf, -1, NULL, 0); char *pcBuf = new char[nReturn]; LCMapString(LOCALE_SYSTEM_DEFAULT, LCMAP_SIMPLIFIED_CHINESE, szBuf, nReturn, pcBuf, nReturn); return pcBuf; } void main() { char* simWord = "中国"; char* traWord = Simple2Tra(simWord); cout << simWord << "->" << traWord << endl; char* simWord2 = Tra2Simple(traWord); cout << traWord << "->" << simWord2 << endl; }
LCMAP_SIMPLIFIED_CHINESE表示traditional Chinese字符集到simplified Chinese字符集的映射,LCMAP_TRADITIONAL_CHINESE相反。函数参数可参见msdn。
2.简体中文和繁体中文(Big5)的转换
大多数情况下简繁的转化是GBK字符集内部的相互映射,但是有时我们会碰到另一种常见的繁体编码:“大五码”。Big5码是一套双字节字符集,BIG5码是通行于*、香港地区的一个繁体字编码方案,其对应代码页为950。首先来看繁体Big5与繁体GBK编码的相互转化,它们二者通过Unicode字符集相关联,Big5<—>Unicode<—>GBK,类似思想可参见此文,程序实现如下
//中國->い瓣 //繁体GBK转Big5码 char* GBK2BIG5(char* szBuf) { int wcsLen = ::MultiByteToWideChar(CP_ACP, NULL, szBuf, -1, NULL, 0); wchar_t* wszString = new wchar_t[wcsLen]; ::MultiByteToWideChar(CP_ACP, NULL, szBuf, -1, wszString, wcsLen); //CP_ACP本地编码(GBK)对应代码页 int ansiLen = ::WideCharToMultiByte(950, NULL, wszString, -1, NULL, 0, NULL, NULL); char* szAnsi = new char[ansiLen]; ::WideCharToMultiByte(950, NULL, wszString, -1, szAnsi, ansiLen, NULL, NULL); //Big5对应代码页 delete[] wszString; return szAnsi; } //い瓣->中國 //Big5码转繁体GBK char* BIG52GBK(char* szBuf) { int wcsLen = ::MultiByteToWideChar(950, NULL, szBuf, -1, NULL, 0); wchar_t* wszString = new wchar_t[wcsLen]; ::MultiByteToWideChar(950, NULL, szBuf, -1, wszString, wcsLen); //Big5对应代码页 int ansiLen = ::WideCharToMultiByte(CP_ACP, NULL, wszString, -1, NULL, 0, NULL, NULL); char* szAnsi = new char[ansiLen]; ::WideCharToMultiByte(CP_ACP, NULL, wszString, -1, szAnsi, ansiLen, NULL, NULL); //CP_ACP本地编码(GBK)对应代码页 delete[] wszString; return szAnsi; }
上述程序实现了繁体字下GBK和Big5码的相互转化,由于简体中文操作系统中ANSI默认是GBK编码,“中國”二字转码为Big5码后,系统仍然按照GBK编码进行解析后显示,这样势必是乱码的。如果想要得到Big5编码下的正确显示,可以更改系统的语言,将Big5作为其默认ANSI即可,如下:打开“控制面板”->“区域和语言”
重启计算机,*地区系统默认使用Big5码。如果刚才把GBK->Big5的结果保存到txt中,这时会发现txt文档中保存的“い瓣”变成了“中國”。在Big5编码下,有些大陆的网页可能会显示乱码,建议再改回原来的设置。
上述实现了繁体字GBK和Big5码的转化。如果想要将简体中文转化到Big5码,可以通过“简体中文GBK->繁体中文GBK->繁体Big5 ”的方式实现,第一步是GBK码内的映射,第二步是两种编码间的转化;反之亦然。