实验目的
1.深入理解汉字在计算机内的存储形式,熟悉GBK、Big-5和Unicode中汉字的分布与编码规律。
2.理解简 繁(繁 简)汉字转换的需求、应用与困难。
3.掌握简 繁(繁 简)汉字机内码转换的技术。
实验内容
1.设计一个ISO10646-1:1993/Unicode内码和GBK内码的转换表结构。
2.编写程序构建ISO10646-1:1993/Unicode内码和GBK内码的转换表。
3.编写应用程序,实现ISO10646-1:1993/Unicode内码和GBK内码在文件级的转换。
预备知识
一、ISO10646-1:1993/Unicode、GBK与Big-5
·GBK
GBK全称“汉字内码扩展规范”,英文名称为Chinese Internal Code Specification,由中华人民共和国全国信息技术标准化技术委员会于1995年12月制定。GB即“国标”,K是“扩展”的汉语拼音第一个汉字的第一个字母。
GBK在编码上与GB2312—80兼容,在字汇上与ISO10646兼容。实质上,它是一个用于从GB2312—80向ISO10646过渡的产物。
与GB2312—80一样,GBK也采用了双字节表示,总体编码范围是8140H~FEFEH,首字节在81H~FEH之间,尾字节在40H~FEH之间,剔除了xx7FH一条线。GBK总计有23940个码位,共收录了21886个汉字和图形符号,其中汉字(包括部首和构件)有21003个,图形符号有883个。
GBK的编码结构如表2.1所示。汉字的内码分布在GBK/2(B0A1H~F7FEH)、GBK/3(8140H~A0FEH)、GBK/4(AA40H~FEA0H)中,共有21003个。
表2.1 GBK的编码结构
·Big-5
Big-5码是一个通行于台湾、香港地区的繁体汉字编码方案,它被俗称为“大五码”或“五大码”。1984年,台湾地区13家厂商试图合力开发“文字处理”“数据库”“电子表格”“通讯”和“绘图”五大套装软件。虽然开发出来的软件未获成功,但为开发五大套装软件设计的Big-5码却成为了业界的主流,后来发展成为了繁体中文使用地区的标准。
Big-5码共收录汉字13053个,它包含5401个常用字和7652个次常用字两部分。常用字包括台湾地区教育管理部门颁布的《常用汉字标准字体表》中的全部汉字4808个,台湾地区中小学教科书常用字587个,异体字6个;次常用字包括台湾地区教育管理部门颁布的《次常用汉字标准字体表》的全部汉字6341个和《罕用汉字标准字体表》中使用频率较高的1311个汉字。
Big-5同样是一个双字节编码,高位字节在81H~FEH之间,低位字节在40H~7EH以及A1H~FEH。
需要注意的是,应该是由于工作中的疏忽,Big-5中重复收录了两个相同的字。“兀”有A461H和C94AH两个编码,“嗀”也有DCD1H和DDFCH两个编码。因为在文件和互联网上检索字符往往需要作字符内码的精确匹配,一个字有多个内码会导致查询结果的查全率很差。
·ISO10646-1:1993/Unicode中的汉字分布
ISO10646-1:1993/Unicode的BMP平面中从4E00H到9FFFH是中日韩认同的表意文字区,合计收录了20902个中日韩汉字。
二、Unicode与文本文件
GB2312—80中每个汉字的机内码由于最高字节一定为1,因此可以有效地和ASCII区分开来。但Unicode内码的机内码并没有类似的明显区分方法,因此如果将一段汉字以Unicode内码存储到文本文件中,将来在读取的时候很有可能误将其中的数据按照ANSI Code或者ASCII进行解析,这样同样可能会导致“乱码”。
在Windows的文本文件中是通过添加特殊标记文件头来解决该问题的。Windows操作系统附带的记事本程序在存储Unicode文本文件时,会在文件最前面存储了一个FFFEH标记。该标记占用了两个字节,接着在后面存储正常文本每个字符的Unicode内码。由于FFFEH码位在ANSI Code和Unicode中都没有被使用,因此不存在二义性,这是一种很简单有效的区分Unicode与ANSI Code文本文件的方法。
三、汉字的简-繁(繁-简)转换的需求
个人、企业、组织和政府部门都有大量的简-繁(繁-简)汉字转换的需求。例如,中国内地的电子邮件使用者,将一个采用GBK编码存储汉字的邮件发送给香港地区的用户,那么对方很有可能会看到一个充满了“乱码”的邮件。图2.1显示了同一邮件采用不同编码查看而出现的“乱码”。此外,很多跨境的组织机构、公司希望自己网站上发布的最新信息和新闻能够便捷地实现简 繁体同步更新,同样大量软件公司在开发国际化软件的时候也希望自己的软件能够同时支持简繁体中文。
图2.1 GBK编码的邮件采用Big-5编码查看时出现“乱码”
汉字简 繁转换需求大致可以分成三个层次,第一个层次是内码层,保证在简(繁)体平台中撰写的文档在繁(简)体平台显示时不是乱码;第二个层次是字形层,在内码层的基础上保证简(繁)体汉字转换为对应的字形,如简体“软件”转换为繁体“軟件”;第三个层次是词汇层,在字形层的基础上需要保证转换过去的词汇符合对方的文化背景以及固定搭配,如简体“软件”需要转换为繁体“軟體”,才能真正方便香港和台湾地区的用户查看。
如果说内码层转换是为了让对方不“乱码”,字形层转换是为了让对方“看得懂”,那么词汇层转换就是让对方“看得舒服”。
实验原理
借助于系统的API函数,可以在Windows操作系统中对汉字的内码在Unicode和本地编码(如GBK、Big-5)之间方便地进行转换。
Windows API函数MultiByteToWideChar可用于将ANSI Code字符串(也称多字节字符串)转换成Unicode字符串(宽字符串)。MultiByteToWideChar函数的声明如下:
intMultiByteToWideChar(
UINT CodePage, //code page
DWORD dwFlags, //character-type options
LPCSTR lpMultiByteStr, //string to map
int cbMultiByte, //number of bytes in string
LPWSTR lpWideCharStr, //wide-character buffer
int cchWideChar //size of buffer
);
CodePage参数用于标识一个与ANSI Code字符串相关的代码页号。其中,简体中文的代码页是936,繁体中文的代码页是950,韩文的代码页是949。如果该参数填写CP-ACP,则表示采用与调用本函数的Windows系统相同的代码页,该参数也可以是CP-UTF7或CP-UTF8。
dwFlags参数用于控制一些特殊字符的转换,在处理中文时这些标志通常并不使用,一般在dwFlags参数中传递0。
lpMultiByteStr参数用于指定待转换的ANSI Code字符串的首地址。
cbMultiByte参数用于指明待转换字符串的长度(按字节计算)。如果调用本函数时cbMultiByte参数传递-1,那么待转换的字符串必须以NULL作为结束符,此时函数将自己计算出待转换字符串的长度。
lpWideCharStr参数指定转换后产生的Unicode字符串将被写入内存中的缓存地址。
cchWideChar参数用于描述存储转换后Unicode字符串缓冲区的大小(以字符而不是字节为计量单位)。如果调用MultiByteToWideChar时,给cchWideChar参数传递0,那么该函数将不执行字符串的转换,而是返回存储转换后Unicode字符串所需缓冲区的大小。
一般来说,可以通过下列步骤将多字节字符串转换成Unicode等价字符串:
(1)调用MultiByteToWideChar函数时,将pWideCharStr参数传递NULL,将cchWide-Char参数传递0,从而可以得到所需要的缓冲区大小。
(2)根据上一步的返回值分配足够的内存块,用于存放转换后的Unicode字符串。
(3)再次调用MultiByteToWideChar,这次将刚分配内存的首地址作为lpWideCharStr参数来传递,并传递第一次调用MultiByteToWideChar时返回的缓存大小作为cchWide-char参数。
(4)使用转换后的字符串。
(5)释放Unicode字符串占用的内存块。
Windows API函数WideCharToMultiByte用于将Unicode字符串转换成ANSI Code字符串。WideCharToMultiByte函数的声明如下:
int WideCharToMultiByte(
UINT CodePage, //code page
DWORD dwFlags, //performance and mapping flags
LPCWSTR lpWideCharStr, //wide-character string
int cchWideChar, //number of charsin string
LPSTR lpMultiByteStr, //buffer for new string
int cbMultiByte, //size of buffer
LPCSTR lpDefaultChar, //default for unmappable chars
LPBOOL lpUsedDefaultChar //set when default char used
);
其中参数codePage、dwFlags、lpWideCharStr和cchWideChar的意义同MultByteToW-ideChar的对应参数。
lpWideCharStr参数用于设定要转换的Unicode字符串,转换产生的ANSI Code字符串被写入由lpMultiByteStr参数指明的缓冲区。
由于Unicode的字符数量往往超过各种本地代码页中的字符数量,所以就存在有字符不能转换为ANSI Code的可能。因此,本函数比MultiByteToWideChar函数多出来了两个参数,即lpDefaultChar和lpUsedDefaultChar。当Wide CharToMultiByte函数遇到一个在CodePage参数标识的代码页中没有对应符号的Unicode字符时,WideCharToMultiByte函数就使用这两个参数。例如,把简化汉字“国”的Unicode内码转换为Big-5内码时,在Big-5中没有此简化字对应的编码,将会转换失败。如果一个Unicode字符不能被转换为指定代码页的符号,该函数便使用lpDefaultChar参数指向的字符。如果该参数是NULL (这是大多数情况下的参数值),那么该函数使用系统的默认字符,该默认字符通常是个问号。lpUsedDefaultChar参数指向一个布尔变量,如果Unicode字符串中至少有一个字符不能转换成等价多字节字符,那么函数就将该变量置为TRUE。如果所有字符均被成功地转换,那么该函数就将该变量置为FALSE。当函数返回后可以通过检查该参数带回的值来判断是否所有的Unicode字符被成功地转换。
通过将每个汉字的内码作为参数调用前面的两个函数之一,就可以方便地建立一张GBK中所有汉字内码到ISO10646-1:1993/Unicode内码的映射关系表,同样也可以构造出Big-5中所有汉字内码到ISO10646-1:1993/Unicode内码的映射关系表。借助于这两张映射表,就可以自己编写程序实现简 繁(繁 简)内码层的转换。
实验环境
一、操作系统
Windows 2000以上版本,例如,Windows 2000/XP/Vista/7/8/8.1/10等。
二、开发环境
Visual Studio 6.0以上版本,例如,Visual Studio 6.0/2003/2005/2008/2010/2012/2013等。
三、应用程序
Microsoft Office 2003以上版本。
实验步骤
1.设计ISO10646-1:1993/Unicode内码和GBK内码映射表的结构,请在实验报告中描述出你所设计的结构。
注意:一个好的映射表不仅要便于查找,而且要节约存储。
2.建立一个Win32 Console Application,该程序生成ISO10646-1:1993/Unicode内码和GBK内码转换表,请在实验报告中给出你的实现代码。
3.设计一个基于文件的ISO10646-1:1993/Unicode内码和GBK内码转换程序,请给出转换算法。
注意:本程序应该不依赖MultiByteToWideChar和WideCharToMultiByte这两个Win-dows API函数,否则本程序将只能运行在Windows平台。
4.检查程序执行结果。
(1)用Windows附带的记事本程序编辑一个Unicode的文本文件,文件内容如下:
100年来,苏州大学先后向社会输送25万多名大学生和研究生,其中许多人已成为科学教育文化等各项事业中的著名学者和知名人士。
用该文件作为你的ISO10646-1:1993/Unicode内码和GBK内码转换程序的输入,请在实验报告中填写该程序的输出结果。
(2)用Windows附带的记事本程序自行组织一些文本,测试你的转换程序。
请在实验报告中填写你的输入文件内容和输出文件的内容。
5.在Microsoft的Word软件中附带了简繁(繁简)转换的功能,可以通过【工具】→【语言】→【中文简繁转换】功能项加以使用,运行界面参见图2.2。显然它在内码转换的同时还实现了词汇级别的转换,此外还提供了用户自定义词典功能。
图2.2 Microsoft的Word提供的中文简 繁转换功能
请将实验步骤4中测试的文本用该工具进行转换,并比较与自己所写程序的差异,请把自己分析的有差异的原因填写在实验报告中。
思考题
1.分析你所设计的ISO10646-1:1993/Unicode内码和GBK内码映射表结构的优点和缺点。
2.如果在ISO10646-1:1993/Unicode内码和GBK内码转换时,文件中有ASCII字符,应该如何处理?
3.如何将GBK内码的文件转为Big-5内码?请思考并设计一个方案。
4.在思考题3的基础上考虑如何保证“发财”“理发”的两个“发”字被分别正确转换为“發”和“髪”字。
5.通过互联网查找两到三个简 繁内码转换工具,进行试用,并对比它们的优缺点。
[1]王立军,王晓明,吴健.简繁对应关系与简繁转换[J].中文信息学报,2013,27(4):74-82.
[2]郭小武.电子文本的简繁转换——关于简体古籍逆向工程的实验报告[J].语言文字应用, 2000,(4):79-86.
[3]MultiByteToWideChar function.https://msdn.microsoft.com/en-us/library/dd319072(VS.85).as-px.
[4]WideCharToMultiByte function.https://msdn.microsoft.com/en-us/library/dd374130(vs.85).as-px.
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。