在处理套打程序时用到TextOut,但TextOut无法自动换行,只好动手写代码,可是处理到汉字部分时卡住了,搜索网上判断汉字的帖子,都语焉不详,经过一下午的研究,终于整理出一个简单的教程。
其实判断汉字的代码很简单,简单到只有一行就可以了,但不理解汉字编码的基础,这一行代码却万万无法理解。
常用的字符编码有以下三种:
1、ASCII 只支持英文,全部为8位
2、DBCS 支持英文和中文,但中文需要两个字节(16位)
3、UNICODE 支持英文和中文,英文和中文都需要两个字节
ASCII是DOS时代的,无法支持中文。DBCS是Win9x支持的字符集。UNICODE是win2k和xp支持的字符集。
而汉字的编码目前有GB2312-1980和GB18030-2000,GB2312就是DBCS类型的汉字编码,GB18030就是UNICODE的汉
字编码,当然GB18030兼容GB2312,也就是说GB18030也支持DBCS的字符处理方式。虽然GB18030是2000年后强制执行的国家标
准,但目前使用最多的还是GB2312编码,而且GB2312也足够处理你所用到的汉字了。还有GBK编码是GB2312的增强版。
这里我仅支持GB2312。由于GB2312是中国大陆制定的标准,所以繁体中文并不在GB2312的编码中,如果你的程序需要支持繁体中文,则还需要处理Big5编码。其实也很简单。
下面说一下在C中如何处理GB2312编码的汉字。以VC6.0为例,如果声明变量的类型为wchar_t则是UNICODE编码,如果是char则是DBCS编码比如我的一个函数声明是:
void Justify (HDC hdc, PTSTR pText, RECT * prc, int iAlign)
其中的pText是PTSTR类型,PTSTR在WINNT.H中有两个定义(WINNT.H中的这段代码我删掉了中间无关的部分)
#ifdef UNICODE
typedef LPWSTR PTSTR, LPTSTR; //如果是UNICODE编码,则定义PTSTR为LPWSTR类型
#else
typedef LPSTR PTSTR, LPTSTR; //如果是不是UNICODE编码,则定义PTSTR为LPSTR类型
#endif
LPSTR定义为CHAR的指针
LPSWSTR定义为WCHAR的指针
CHAR定义为char类型
WCHAR定义为wchar_t类型
而wchar_t定义为unsigned short类型,它是16位,两个字节,无符号短整数
是UNICODE还是非UNICODE取决于你的编译选项,如果在[工程]-[选项]-[C/C++]的[预处理程序定义]中填入了_UNICODE,那
么程序会用wchar_t指针来定义LPSTR,如果没有_UNICODE,那么程序会用char指针来定义LPSTR,这样带来的区别就是,你接受到的
pText中的字节内容是不一样的,[i服了you]这个字串如果在没有定义_UNICODE的情况下,是8个字节,而在定义了_UNICODE的情况下
是12个字节。反映到程序中就是,如果没有定义_UNICODE,那么就要把英文字符当成1个字节来处理,而汉字字符的编码是采用GB2312编码规范来
的;如果定义了_UNICODE,那么英文字符要当成2个字节来处理,而汉字字符的编码是采用UNICODE编码来的。举例来说,win98不采用
UNICODE编码而采用的是DBCS编码,为了让我的程序既可以在XP下运行又可以在Win98下运行,我没有定义_UNICODE。这样我的程序代码
就要把字符串当成DBCS编码来处理,也就是英文字符是1个字节,中文字符是2个字节,中文编码采用GB2312编码。用Justify来说明:
我给pText传递来[你]这个汉字,那么pText应该有两个字节来存放[你]这个字,设置段点来读一下pText的内容。
void Justify (HDC hdc, PTSTR pText, RECT * prc, int iAlign)
{
static TCHAR szText[] = {TEXT ("你")} ;
pText=szText;
}
设断调试会发现*pText=-60,怎么会这样呢,原因是没有按unsigned char来转换*pText的值,修改代码如下:
void Justify (HDC hdc, PTSTR pText, RECT * prc, int iAlign)
{
static TCHAR szText[] = {TEXT ("你")} ;
unsigned char sqChar[20]; //这个变量就是为了强制转换类型用的
pText=szText;
sqChar[0]=*pText;
sqChar[1]=*(pText+1);
}
这时下断查看sqChar[0]=196,sqChar[1]=227就对了,为什么呢,因为它和GB2312的编码是一样的。
GB2312-80编码的编码范围是高位0xa1-0xfe,低位是 0xa1-0xfe ,其中汉字范围为 0xb0a1 和
0xf7fe,如果只是简单地判断汉字,则只要查看高字节是否大于等于0xa1就可以了,还有就是,全角字符的高字节统统等于0xa3,所以很容易可以区
别出全角字符来。
如果你希望你的程序能支持到GB18030,那么就去找GB18030的规范来看看。
网上有很多判断汉字的说法,你只要记住,你要支持的编码是哪个?GB2312、GBK、GB18030?每个编码有自己的编码范围或者规范,网上之所以有
不同的说法,正是因为他们互相说的不是同一种编码方式。我这里说的是GB2312的编码,如果你的程序要编译成支持UNICODE的话,那么这段代码就要
修改成对应UNICODE规范的代码了。
附简单的测试汉字、全角字符、英文的程序:
//test.c
//源代码作者:夏克
//新建Win32 Application工程,把test.c加入,运行,试着修改szText的值,来观察代码效果
#include
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szText[] = {TEXT ("i服,了。uy")} ;
PTSTR pText;
int i;
unsigned char sqChar[20];
pText=szText;
while (*pText != '\0')
{
i=IsGB(pText);
switch(i)
{
case 0:
pText++;
MessageBox (NULL, TEXT ("发现数字、英文字符或英文标点"), TEXT ("Hello"), 0);
break;
case 1:
pText++;
pText++;
MessageBox (NULL, TEXT ("发现全角字符"), TEXT ("Hello"), 0);
break;
case 2:
pText++;
pText++;
MessageBox (NULL, TEXT ("发现汉字"), TEXT ("Hello"), 0);
break;
}
}
return 0 ;
}
int IsGB(PTSTR pText)
{
unsigned char sqChar[20];
sqChar[0]=*pText;
if (sqChar[0]>=0xa1)
if (sqChar[0]==0xa3)
return 1; //全角字符
else
return 2; //汉字
else
return 0; //英文、数字、英文标点
}
汉字在电脑中的编码处理简介 GB2312/GBK/GB18030/BIG5
中文字符编码简介 GB2312/GBK/GB18030/BIG5
1 GB2312-80
GB2312码是中华人民共和国国家汉字信息交换用编码,全称《信息交换用汉字编码字符集——基本集》,由国家标准总局发布,1981年5月1日实施,通行于大陆。新加坡等地也使用此编码。
GB2312收录简化汉字及符号、字母、日文假名等共7445个图形字符,其中汉字占6763个。GB2312规定“对任意一个图形字符都采用两个字节表示,每个字节均采用七位编码表示”,习惯上称第一个字节为“高字节”,第二个字节为“低字节”。
GB2312
将代码表分为94个区,对应第一字节;每个区94个位,对应第二字节,两个字节的值分别为区号值和位号值加32(2OH),因此也称为区位码。01-09
区为符号、数字区,16-87区为汉字区,10-15区、88-94区是有待进一步标准化的空白区。GB2312将收录的汉字分成两级:第一级是常用汉字
计3755个,置于16-55区,按汉语拼音字母/笔形顺序排列;第二级汉字是次常用汉字计3008个,置于56-87区,按部首/笔画顺序排列。故而
GB2312最多能表示6763个汉字。
GB2312的编码范围为2121H-777EH,与ASCII有重叠,通行方法是将GB码两个字节的最高位置1以示区别。
2 GBK
GB2312
-80仅收汉字6763个,这大大少于现有汉字,随着时间推移及汉字文化的不断延伸推广,有些原来很少用的字,现在变成了常用字,例如:朱镕基的“镕”
字,未收入GB2312-80,现在大陆的报业出刊只得使用(金+容)、(金容)、(左金右容)等来表示,形式不一而同,这使得表示、存储、输入、处理都
非常不方便,对于搜索引擎等软件的构造来说也不是好消息,而且这种表示没有统一标准。从我们对人民日报98年数据的处理过程中,得出这样的经验:回填外字
最困难的就是如何得到这种表示方法的集合。
为了解决这些问题,以及配合UNICODE的实施,全国信息技术化技术委员会于1995年12
月1日《汉字内码扩展规范》。GBK向下与GB2312 完全兼容,向上支持ISO
10646国际标准,在前者向后者过渡过程中起到的承上启下的作用。GBK
亦采用双字节表示,总体编码范围为8140-FEFE之间,首字节在81-FE之间,尾字节在40-FE之间,剔除XX7F一条线。
GBK共收入21886个汉字和图形符号,包括:
* GB2312中的全部汉字、非汉字符号。
* BIG5中的全部汉字。
* 与ISO 10646相应的国家标准GB13000中的其它CJK汉字,以上合计20902个汉字。
* 其它汉字、部首、符号,共计984个。
微软公司自Windows 95 简体中文版开始支持GBK代码,但目前的多数搜索引擎都不能很好地支持GBK汉字。
GBK编码区分三部分:
* 汉字区 包括
GBK/2:OXBOA1-F7FE, 收录GB2312汉字6763个,按原序排列;
GBK/3:OX8140-AOFE,收录CJK汉字6080个;
GBK/4:OXAA40-FEAO,收录CJK汉字和增补的汉字8160个。
* 图形符号区 包括
GBK/1:OXA1A1-A9FE,除GB2312的符号外,还增补了其它符号
GBK/5:OXA840-A9AO,扩除非汉字区。
* 用户自定义区
即GBK区域中的空白区,用户可以自己定义字符。
3 GB18030
GB18030 是最新的汉字编码字符集国家标准, 向下兼容 GBK 和 GB2312 标准。 GB18030
编码是一二四字节变长编码。一字节部分从 0x0~0x7F 与 ASCII 编码兼容。 二字节部分, 首字节从 0x81~0xFE, 尾字节从
0x40~0x7E 以及 0x80~0xFE, 与 GBK标准基本兼容。 四字节部分, 第一字节从 0x81~0xFE, 第二字节从
0x30~0x39, 第三和第四字节的范围和前两个字节分别相同。 四字节部分覆盖了从 0x0080 开始, 除去二字节部分已经覆盖的所有
Unicode 3.1 码位。也就是说, GB18030 编码在码位空间上做到了与 Unicode 标准一一对应,这一点与 UTF-8
编码类似。
目前最新的 glibc 2.2.x 系列已经全面支持了 GB18030 Locale 和 GB18030 与 UCS-4
之间的编码转换, 也就是说在系统层上 Linux 已经可以支持 GB18030 标准了。 下面问题的关键就是怎样让 XFree86
窗口系统也支持 GB18030 标准。
4 BIG5
BIG5是通行于台湾、香港地区的一个繁体字编码方案。虽然存在一些瑕疵,但广泛应用于电脑行业,尤其是互联网中,从而成为一种事实上的行业标准。
1983年10月,台湾国家科学委员会、教育部国语推行委员会、中央标准局、行政院共同制定了《通用汉字标准交换码》,后经修订于1992年5月公布,更名为《中文标准交换码》,BIG5是台湾资讯工业策进会根据以上标准制定的编码方案。
BIG5码是双字节编码方案,其中第一个字节的值在OXAO-OXFE之间,第二个字节在OX40-OX7E和OXA1-OXFE之间。
BIG5收录13461个汉字和符号,包括:
* 符号408个,编码位置A140-A3BE
* 常用字5401个,编码位置A440-C67E,包括台湾教育部颁布的《常用国字标准字体表》的全部汉字4808个,台湾教科书常用字587个,异体字6个。
* 次常用字7652个,编码位置C940-F9D5,包括台湾教育部颁布的《次常用国字标准字体表》的全部汉字6341个,《罕用国字标准字体表》中使用频率较高的字1311个。
来自:%D5%D4%B7%F6%B7%E7/blog/item/70db3afd03f5101f09244df9.html
阅读(7307) | 评论(0) | 转发(0) |