VC++中如何获取GB2312字符集中汉字拼音首字母

一、关于GB2312编码的必要知识

GB2312编码适用于汉字处理、汉字通信等系统之间的信息交换,通行于中国大陆;新加坡等地也采用此编码。中国大陆几乎所有的中文系统和国际化的软件都支持GB 2312。1995年又颁布了《汉字编码扩展规范》(GBK)。GBK与GB 2312—1980国家标准所对应的内码标准兼容,同时在字汇一级支持 ISO/IEC10646—1 和 GB 13000—1 的全部中、日、韩(CJK)汉字,共计20902字。

1 分区表示

基本集共收入汉字6763个和非汉字图形字符682个。整个字符集分成94个区,每区有94个位。每个区位上只有一个字符,因此可用所在的区和位来对汉字进行编码,称为区位码。
01-09区为特殊符号。
16-55区为一级汉字,按拼音排序。
56-87区为二级汉字,按部首/笔画排序。
10-15区及88-94区则未有编码。
举例来说,“啊”字是GB2312之中的第一个汉字,它的区位码就是1601

2 国标码和计算机机内码

把换算成十六进制的区位码加上2020H,就得到国标码。国标码加上8080H,就得到常用的计算机机内码
说到这里,有同学要问了,区位码不是已经可以表示汉字了吗?为什么还要搞出来了国标码和计算机内码?听我给你慢慢道来。
GB2312虽然说是对中文编码,但是里面有对26个英文字母和一些特殊符号的编码,按理说这和ASCII重合的部分应该无需设置,沿用ASCII中不就行了?但是当时在制定GB2312之前,就决定覆盖掉ASCII中符号和英文字母部分,所以将其中的英文字母和符号重新编入GB2312中。而对于ASCII中前32个控制字符则继续沿用。所以保留前32字符,就需要将汉字编码向后偏移32,十六进制20H,这也就是区位码要加上20H得到国标码,这就是GB2312的编码规范。
好了,解释清楚为什么要从区位码转为国标码,那为什么国标码还要转为机内码呢?这是为了避免和ASCII码编码的字符冲突。还以“啊”为例,它的区位码为1601,那么国标码就是区码和位码分别加上20H,得到3021H,那么计算机在读取这个数字的时候,首先读取30,是个控制位,然后读取21,还是个控制位,这样就会出现乱码。为了解决这个问题,汉字机内码就横空出世了。
先说定义,汉字的机内码是计算机系统内部对汉字进行存储、处理、传输统一使用的代码,又称为汉字内码。大家要明白,计算机在实际存储一个汉字时,实际上存储的不是区位码或者国标码,而是机内码。而机内码实际上是汉字的区位码分别加上A0H。因为ASCII中使用7位,最高位为0;而汉字的机内码在区位码加上A0H后,字节的最高位变为1了,这样就区分开了ASCII和GB2312。
还以“啊”为例,它的区位码是1601,但实际上它在计算机内部存储的的编码(假定执行时采用GBK编码方式)是B0A1H(注意,存储的第一个字节为B0,第二个字节为A1).

3 字节结构

在使用GB2312的程序中,通常采用EUC储存方法,以便兼容于ASCII。每个汉字及符号以两个字节来表示。第一个字节称为“高位字节”(也称“区字节”),第二个字节称为“低位字节”(也称“位字节”)。

“高位字节”使用了0xA1-0xF7(把01-87区的区号加上0xA0),“低位字节”使用了0xA1-0xFE(把01-94加上 0xA0)。 由于一级汉字从16区起始,汉字区的“高位字节”的范围是0xB0-0xF7,“低位字节”的范围是0xA1-0xFE,占用的码位是 72*94=6768。其中有5个空位是D7FA-D7FE。

了解了上述基础知识之后,我们就可以知道了,计算机获取了汉字的ANSI编码之后,高位字节和低位字节分别减去0Xa0之后,就可以得到区位码。再根据汉字的区位码,确定汉字是一级还是二级汉字,确定其拼音首字母。

二、代码实现

//该函数可以获取一个汉字字符串的拼音首字母
//strSrc为输入的源字符串,strResult为返回的拼音首字母字符串
void GetWord1stLetter(const CString& strSrc, CString & strResult)
{
	strResult.Empty();
	if (strSrc.IsEmpty())
		return;

	byte ucHigh, ucLow;
	int nCode;
	CString strRet;

	//由于GetString返回的是wchar_t类型的字符串,而宽字符类型在程序执行时采用Unicode编码规范,
	//UTF-16编码方式;因此,为了找出和GB2312的对应关系,需要首先转换为ANSI编码方式
	std::string strAnsi = CT2A(strSrc.GetString());
	size_t nLength = strAnsi.length();
	for (size_t i = 0; i < nLength; i++)
	{
		if ((unsigned)strAnsi[i] < 0x80)	//accii码
		{
			strResult += strAnsi[i];
			continue;
		}

		//获取汉字的区位码。由于汉字的机内码采用EUC-CN编码方式,因此第1个字节就是高位字节,
		//第2个字节就是低位字节,这两个字节分别减去0xa0,就是汉字的区位码
		if (i + 1 < nLength)	//防止越界
		{
			ucHigh = (byte)strAnsi[i];
			ucLow = (byte)strAnsi[i + 1];
			if (ucHigh < 0xa1 || ucLow < 0xa1)
				continue;
			else
				nCode = (ucHigh - 0xa0) * 100 + ucLow - 0xa0;

			GetChs1stLetter(nCode, strRet);
			strResult += strRet;
			i++;
		}
	}
}

//该接口根据汉字区位码获取汉字的拼音首字符
void GetChs1stLetter(int nCode, CString& strLetter)
{
	if (nCode <= 1600)
		return;

	//一级汉字按照拼音顺序排序,该数组存储汉字拼音分隔位置
	static int ari1stSecPosValue[] =
	{
		1601, 1637, 1833, 2078, 2274, 2302, 2433, 2594, 2787, 3106, 3212,
		3472, 3635, 3722, 3730, 3858, 4027, 4086, 4390, 4558, 4684, 4925, 5249
	};

	//存储汉语拼音的首字母
	static TCHAR psz1stLetter[] = _T("ABCDEFGHJKLMNOPQRSTWXYZ");

	//存储二级汉字拼音的首字母
	static TCHAR psz2ndSecTbl[] =
		_T("CJWGNSPGCGNE[Y[BTYYZDXYKYGT[JNNJQMBSGZSCYJSYY[PGKBZGY[YWJKGKLJYWKPJQHY[W[DZLSGMRYPYWWCCKZNKYYGTTNJJNYKKZYTCJNMCYLQLYPYQFQRPZSLWBTGKJFYXJWZLTBNCXJJJJTXDTTSQZYCDXXHGCK[PHFFSS[YBGXLPPBYLL[HLXS[ZM[JHSOJNGHDZQYKLGJHSGQZHXQGKEZZWYSCSCJXYEYXADZPMDSSMZJZQJYZC[J[WQJBYZPXGZNZCPWHKXHQKMWFBPBYDTJZZKQHY")		
		_T("LYGXFPTYJYYZPSZLFCHMQSHGMXXSXJ[[DCSBBQBEFSJYHXWGZKPYLQBGLDLCCTNMAYDDKSSNGYCSGXLYZAYBNPTSDKDYLHGYMYLCXPY[JNDQJWXQXFYYFJLEJPZRXCCQWQQSBNKYMGPLBMJRQCFLNYMYQMSQYRBCJTHZTQFRXQHXMJJCJLXQGJMSHZKBSWYEMYLTXFSYDSWLYCJQXSJNQBSCTYHBFTDCYZDJWYGHQFRXWCKQKXEBPTLPXJZSRMEBWHJLBJSLYYSMDXLCLQKXLHXJRZJMFQHXHWY")
		_T("WSBHTRXXGLHQHFNM[YKLDYXZPYLGG[MTCFPAJJZYLJTYANJGBJPLQGDZYQYAXBKYSECJSZNSLYZHSXLZCGHPXZHZNYTDSBCJKDLZAYFMYDLEBBGQYZKXGLDNDNYSKJSHDLYXBCGHXYPKDJMMZNGMMCLGWZSZXZJFZNMLZZTHCSYDBDLLSCDDNLKJYKJSYCJLKWHQASDKNHCSGANHDAASHTCPLCPQYBSDMPJLPZJOQLCDHJJYSPRCHN[NNLHLYYQYHWZPTCZGWWMZFFJQQQQYXACLBHKDJXDGMMY")
		_T("DJXZLLSYGXGKJRYWZWYCLZMSSJZLDBYD[FCXYHLXCHYZJQ[[QAGMNYXPFRKSSBJLYXYSYGLNSCMHZWWMNZJJLXXHCHSY[[TTXRYCYXBYHCSMXJSZNPWGPXXTAYBGAJCXLY[DCCWZOCWKCCSBNHCPDYZNFCYYTYCKXKYBSQKKYTQQXFCWCHCYKELZQBSQYJQCCLMTHSYWHMKTLKJLYCXWHEQQHTQH[PQ[QSCFYMNDMGBWHWLGSLLYSDLMLXPTHMJHWLJZYHZJXHTXJLHXRSWLWZJCBXMHZQXSDZP")
		_T("MGFCSGLSXYMJSHXPJXWMYQKSMYPLRTHBXFTPMHYXLCHLHLZYLXGSSSSTCLSLDCLRPBHZHXYYFHB[GDMYCNQQWLQHJJ[YWJZYEJJDHPBLQXTQKWHLCHQXAGTLXLJXMSL[HTZKZJECXJCJNMFBY[SFYWYBJZGNYSDZSQYRSLJPCLPWXSDWEJBJCBCNAYTWGMPAPCLYQPCLZXSBNMSGGFNZJJBZSFZYNDXHPLQKZCZWALSBCCJX[YZGWKYPSGXFZFCDKHJGXDLQFSGDSLQWZKXTMHSBGZMJZRGLYJB")
		_T("PMLMSXLZJQQHZYJCZYDJWBMYKLDDPMJEGXYHYLXHLQYQHKYCWCJMYYXNATJHYCCXZPCQLBZWWYTWBQCMLPMYRJCCCXFPZNZZLJPLXXYZTZLGDLDCKLYRZZGQTGJHHGJLJAXFGFJZSLCFDQZLCLGJDJCSNZLLJPJQDCCLCJXMYZFTSXGCGSBRZXJQQCTZHGYQTJQQLZXJYLYLBCYAMCSTYLPDJBYREGKLZYZHLYSZQLZNWCZCLLWJQJJJKDGJZOLBBZPPGLGHTGZXYGHZMYCNQSYCYHBHGXKAMTX")
		_T("YXNBSKYZZGJZLQJDFCJXDYGJQJJPMGWGJJJPKQSBGBMMCJSSCLPQPDXCDYYKY[CJDDYYGYWRHJRTGZNYQLDKLJSZZGZQZJGDYKSHPZMTLCPWNJAFYZDJCNMWESCYGLBTZCGMSSLLYXQSXSBSJSBBSGGHFJLYPMZJNLYYWDQSHZXTYYWHMZYHYWDBXBTLMSYYYFSXJC[DXXLHJHF[SXZQHFZMZCZTQCXZXRTTDJHNNYZQQMNQDMMG[YDXMJGDHCDYZBFFALLZTDLTFXMXQZDNGWQDBDCZJDXBZGS")
		_T("QQDDJCMBKZFFXMKDMDSYYSZCMLJDSYNSBRSKMKMPCKLGDBQTFZSWTFGGLYPLLJZHGJ[GYPZLTCSMCNBTJBQFKTHBYZGKPBBYMTDSSXTBNPDKLEYCJNYDDYKZDDHQHSDZSCTARLLTKZLGECLLKJLQJAQNBDKKGHPJTZQKSECSHALQFMMGJNLYJBBTMLYZXDCJPLDLPCQDHZYCBZSCZBZMSLJFLKRZJSNFRGJHXPDHYJYBZGDLQCSEZGXLBLGYXTWMABCHECMWYJYZLLJJYHLG[DJLSLYGKDZPZXJ")
		_T("YYZLWCXSZFGWYYDLYHCLJSCMBJHBLYZLYCBLYDPDQYSXQZBYTDKYXJY[CNRJMPDJGKLCLJBCTBJDDBBLBLCZQRPPXJCJLZCSHLTOLJNMDDDLNGKAQHQHJGYKHEZNMSHRP[QQJCHGMFPRXHJGDYCHGHLYRZQLCYQJNZSQTKQJYMSZSWLCFQQQXYFGGYPTQWLMCRNFKKFSYYLQBMQAMMMYXCTPSHCPTXXZZSMPHPSHMCLMLDQFYQXSZYYDYJZZHQPDSZGLSTJBCKBXYQZJSGPSXQZQZRQTBDKYXZK")
		_T("HHGFLBCSMDLDGDZDBLZYYCXNNCSYBZBFGLZZXSWMSCCMQNJQSBDQSJTXXMBLTXZCLZSHZCXRQJGJYLXZFJPHYMZQQYDFQJJLZZNZJCDGZYGCTXMZYSCTLKPHTXHTLBJXJLXSCDQXCBBTJFQZFSLTJBTKQBXXJJLJCHCZDBZJDCZJDCPRNPQCJPFCZLCLZXZDMXMPHJSGZGSZZQLYLWTJPFSYASMCJBTZKYCWMYTCSJJLJCQLWZMALBXYFBPNLSFHTGJWEJJXXGLLJSTGSHJQLZFKCGNNNSZFDEQ")
		_T("FHBSAQTGYLBXMMYGSZLDYDQMJJRGBJTKGDHGKBLQKBDMBYLXWCXYTTYBKMRTJZXQJBHLMHMJJZMQASLDCYXYQDLQCAFYWYXQHZ");

	size_t nSecondSecTable = _tcslen(psz2ndSecTbl);
	if (nCode > 1600 && nCode < 5590)  //一级汉字 16-55区
	{
		for (int j = 22; j >= 0; j--)
		{
			if (nCode >= ari1stSecPosValue[j])
			{
				strLetter = psz1stLetter[j];
				break;
			}
		}
	}
	else   //二级汉字 56-87区,通过查表获取拼音首字母
	{
		//根据区位码确定拼音首字母
		int iHiDig = nCode / 100;
		int iLoDig = nCode % 100;
		nCode = (iHiDig - 56) * 94 + iLoDig - 1;
		if (nCode >= 0 && nCode < nSecondSecTable) //其他生僻字不再处理
			strLetter = psz2ndSecTbl[nCode];
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_Santiago

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值