让你的软件支持繁体中文


所属类别:.NET

文章作者:未知

特别推荐:免费发布信息 承包关键词~~抢爆了!HOT!


让你的软件支持繁体中文中国台湾、香港的汉字用的是BIG5编码,而大陆的汉字用的是GB编码(GB2312也好,GBK也好),简体中文软件直接拿到繁体中文环境下运行,问题就出来了。怎么办呢?我们的软件是一款用C#.NET+ASP.NET开发的,所谓B/S型的软件,客户端只须用浏览器访问我们的服务器就行了。很自然的就想到,把代码中的所有的简体字都转换成繁体字,问题不就解决了吗?说干就干。从网上找来了一款转换工具将全部代码文件转换了一遍。编译后运行,发觉静态的文字或提示信息确实已经变成了繁体,但从数据库中拿出来的还是简体(乱码),转换后的各种配置文件也读取出错(因为程序仍然按GB编码的格式进行读取)。还有一个问题,就是源代码只能转换一次。因为第一次转换后GB变成了BIG5,如果再转,就是BIG5转BIG5,结果变得不可辨认。由于源文件非常多,修改维护起来非常麻烦。看来这种方法不可行。那么能不能给我们的软件加上自适应的功能,增加对繁体中文的支持呢?ASP.NET中,页面Page有个对象Response,该对象将HTTP 响应数据发送到客户端,而Response有个获取或设置包装筛选器对象的属性Filter,用于在传输之前修改HTTP 实体主体。当创建Stream 对象并将Response.Filter 属性设置为Stream 对象时,所有由Response.Write 发送的HTTP 输出将通过筛选器。只要我们重载Stream类,在Stream类的Write()方法中将GB码转换成BIG5码,然后将Response.Filter = 重载Stream类,就可以达到在信息输出到客户端前先转换的效果。//页面装载事件private void Page_Load(object sender, System.EventArgs e){ // 在此处放置用户代码以初始化页面 Response.Filter = new CG2BFilter(Response.Filter);//设置筛选器 Response.Charset = “big5”; ……}简体转为繁体类CG2BFilterpublic class CG2BFilter : Stream{…… //重载函数Writepublic override void Write(byte[] buffer, int offset, int count){ WriteGB2BIG(buffer, offset, count);}//简体转为繁体private void WriteGB2BIG(byte[] buffer, int offset, int count) { if( count == 0 ) { return; } //936是简体中文代码页编号 Encoding e = Encoding.GetEncoding(936); string str = e.GetString(buffer,offset,count);//有些简体字没有对应的Big5,所以需要先转换成繁体的GB,再进行转换 for( int i=0;i"; for( byte x = 0x40;x<0xFF;x++ ) {//低字节 buffer[0] = y; buffer[1] = x; //以红色输出汉字,并注明其高低字节值 str += " 0x" + y.ToString("X") + x.ToString("X") + "" + gbe.GetString(buffer) + ""; } } Response.Write(str);然后在浏览器里分别用GB编码和BIG5编码观察,你会发现,这两种编码中,都存在着有些字节值并没有相应的汉字,而是一些奇怪的符号、问号甚至是空白。于是可以这样认为:如果一个汉字的字节值在某种编码中找不到汉字,则说明它不属于这种编码。经过认真比较归纳,两种编码都划定了一些范围,然后可以逐个考察输出流中的汉字,看它是否落在该范围,以此判定它属于何种编码。虽然划定了一些范围,但GB和BIG5重叠的区域实在太多,有许多字用两种编码去套,好象都可以,逐个字转换,误差很大。后来发现了一个很重要的思想,就是:在混合汉字编码的流中,不同的汉字编码总是不相邻的,它们中间有西文字符隔开(因为网页中,控件值都包含在许多HTML标记之间),也就是说,如果有一个汉字确定是某种编码,则可以推断与它相邻的所有汉字都属于同一种编码。事实证明,这种思想使得转换的准确性得到大幅度的提高。修正后的类CG2Bfilter:public class CG2BFilter : Stream{…… public override void Write(byte[] buffer, int offset, int count) { int p = offset; int q = p; int limit = offset + count;//这里定义了两个看似互相矛盾的布尔量:maybeBig,notBig,主要是让它们配合使用。maybeBig表明一段流中出现了有Big5编码特征的汉字,因此可能是大五码但不能肯定,而notBig表明一段流出现了不可能是Big5编码的汉字,则这段流肯定不是大五码。一段流只有在maybeBig为真,且notBig为假时才可能认为它是大五码。 bool maybeBig = false; bool notBig = false; bool isChinese = false; while( p < limit ){ if( buffer[p] >= 0x81 && buffer[p] <= 0xFE ) {//汉字 if( !isChinese ) {//此前不是汉字,先输出 WriteAscii(buffer,q,p-1-q+1);// 待处理的流是西文字符 isChinese = true; q = p; } p++; if( p >= limit ) { break; } if( buffer[p] >= 0x40 && buffer[p] <= 0x7E buffer[p-1] >= 0xA1 && buffer[p-1] <= 0xA3 && buffer[p] >= 0x40 && buffer[p] <= 0xA0 buffer[p-1] >= 0xA4 && buffer[p-1] <= 0xA9 ( buffer[p-1] >= 0xAA && buffer[p-1] <= 0xAF buffer[p-1] >= 0xF8 && buffer[p-1] <= 0xFD ) && buffer[p] >= 0xA1 && buffer[p] <= 0xFE ) {//很可能是BIG5,由此可以推断,这相邻的汉字串都可能是BIG5 maybeBig = true; } if( buffer[p] >= 0x7F && buffer[p] <= 0xA0 buffer[p-1] >= 0x81 && buffer[p-1] <= 0xA0 buffer[p-1] == 0xC6 && buffer[p] >= 0x7F && buffer[p] <= 0x0FE buffer[p-1] >= 0xC7 && buffer[p-1] <= 0xC8 buffer[p-1] == 0xF9 && buffer[p] >= 0xDC buffer[p-1] >= 0xFA ) {//肯定不是BIG,因为在此区间,BIG为空 notBig = true; maybeBig = false; } } else {//非汉字 if( isChinese ) {//此前是汉字,先输出 if( maybeBig && !notBig) { WriteBIG(buffer,q,p-1-q+1);//待处理的流是BIG5 } else {//不肯定是繁体 WriteGB2BIG(buffer,q,p-1-q+1);// 待处理的流是GB } isChinese = false; maybeBig = false; notBig = false; q = p; } } p++; } //将while语句最后一轮循环未处理的部分在这里处理 if( isChinese ) { if( maybeBig && !notBig ) { WriteBIG(buffer,q,p-1-q+1); } else { WriteGB2BIG(buffer,q,p-1-q+1); } } else { WriteAscii(buffer,q,p-1-q+1); } }//处理对象为GBprivate void WriteGB2BIG(byte[] buffer, int offset, int count){……}//处理对象为BIG5private void WriteBIG(byte[] buffer, int offset, int count){……}//处理对象为ASCIIprivate void WriteAscii(byte[] buffer, int offset, int count){……}……}应用修正过的类后,浏览器用BIG5编码浏览运行我们的软件,效果令人非常满意,几乎看不到什么乱码,已经达到了实用的效果。不过繁简切换是一个相当复杂的问题,并不是仅仅是简单地将简体字转换成繁体字就行了,有时还涉及到语义的问题。比如,简体中文中,不论“发展”的“发”还是“头发”的“发”都是同一个字,而在繁体中,它们是不同的两个字。这部分已经超出了笔者现有的水平,不在考虑之列了。关闭本页

相关信息

· 恢复Cisco路由器密码两种常用方法

· 网格服务的未来

· 利用WebBrowser实现Web打印的分析

· 双系统下XP也用Vista的屏幕保护








....

36339 19446