让你的软件支持繁体中文

让你的软件支持繁体中文

中国台湾、香港的汉字用的是 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”;

……

}

简体转为繁体类 CG2BFilter

public class CG2BFilter : Stream

{

……

// 重载函数 Write

public 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

  1<str.length;i++ !="-1" "<font="" (="" )="" +="" 0x40~0x7f="" 0x40~0xff="" 0x81~0xff="" 950="" ;="" _sgb="" _sink.write(e.getbytes(str),0,e.getbytecount(str));="" _tgb="" big5="" buffer="{0,0};" buffer[0]="y;" buffer[1]="x;" byte="" byte[]="" color='\"red\"' e="Encoding.GetEncoding(950);" encoding="" for(="" gb="" gb2312="" gbe="Encoding.GetEncoding(936);" if="" int="" j="" size="4" str="" string="" x="0x40;x&lt;0xFF;x++" x.tostring("x")="" y="0x81;y&lt;0xFF;y++" y.tostring("x")="" {="" }="" ……="" 。一般倾向于认为低字节在="" 与="" 以红色输出汉字,并注明其高低字节值="" 低字节="" 则是对应的="" 将数值从高字节="" 怎么区别呢?="" 是="" 是部分="" 有什么区别吗?很遗憾,并没有什么明显的区别,也就是说,给你一个汉字编码,很难判断它究竟是="" 的。所以这招并非万灵丹。="" 码代码页编号="" 码,因为没有简体字的低字节在这个范围。不过要注意,="" 简体中文字库,="" 繁体字库="" 编码也有繁体字,并且这些繁体字的低字节也有位于="" 编码来加以转换就不行了,要加以区别。="" 编码的基础上的,而大多数情况下也没有什么问题,不过,如果一个页面存在表单控件且控件内有汉字内容随同输出时,那么该页面在运行过程中有回传等刷新动作的话,就可能出现乱码。究其原因,是因为在页面第一次打开时,控件值由简体转成了繁体,回传的时候,则传回服务器的这部分控件值也为繁体。接着再输出,问题就来了:控件值为繁体,而页面本身还是简体,也就是说,输出流中存在混合编码,这样还一刀切将它们认为全是="" 范围的就是="" 还是="" 这样写,是建立在待转换的流全部都是="" 这样组合输出到页面,如下:="" 高字节="" ,低字节="">" + gbe.GetString(buffer) + ""; 
  2
  3} 
  4
  5} 
  6
  7Response.Write(str); 
  8
  9然后在浏览器里分别用  GB  编码和  BIG5  编码观察,你会发现,这两种编码中,都存在着有些字节值并没有相应的汉字,而是一些奇怪的符号、问号甚至是空白。于是可以这样认为:如果一个汉字的字节值在某种编码中找不到汉字,则说明它不属于这种编码。经过认真比较归纳,两种编码都划定了一些范围,然后可以逐个考察输出流中的汉字,看它是否落在该范围,以此判定它属于何种编码。 
 10
 11虽然划定了一些范围,但  GB  和  BIG5  重叠的区域实在太多,有许多字用两种编码去套,好象都可以,逐个字转换,误差很大。后来发现了一个很重要的思想,就是:在混合汉字编码的流中,不同的汉字编码总是不相邻的,它们中间有西文字符隔开(因为网页中,控件值都包含在许多  HTML  标记之间),也就是说,如果有一个汉字确定是某种编码,则可以推断与它相邻的所有汉字都属于同一种编码。事实证明,这种思想使得转换的准确性得到大幅度的提高。 
 12
 13修正后的类  CG2Bfilter  : 
 14
 15public  class  CG2BFilter : Stream 
 16
 17{ 
 18
 19…… 
 20
 21public  override  void  Write(  byte  [] buffer,  int  offset,  int  count) 
 22
 23{ 
 24
 25int  p = offset; 
 26
 27int  q = p; 
 28
 29int  limit = offset + count; 
 30
 31//  这里定义了两个看似互相矛盾的布尔量:  maybeBig  ,  notBig  ,主要是让它们配合使用。  maybeBig  表明一段流中出现了有  Big5  编码特征的汉字,因此可能是大五码但不能肯定,而  notBig  表明一段流出现了不可能是  Big5  编码的汉字,则这段流肯定不是大五码。一段流只有在  maybeBig  为真,且  notBig  为假时才可能认为它是大五码。 
 32
 33bool  maybeBig =  false  ; 
 34
 35bool  notBig =  false  ; 
 36
 37bool  isChinese =  false  ; 
 38
 39while  ( p &lt; limit ) 
 40
 41{ 
 42
 43if  ( buffer[p] &gt;= 0x81 &amp;&amp; buffer[p] &lt;= 0xFE ) 
 44
 45{  //  汉字 
 46
 47if  ( !isChinese ) 
 48
 49{  //  此前不是汉字,先输出 
 50
 51WriteAscii(buffer,q,p-1-q+1);  //  待处理的流是西文字符  isChinese =  true  ; 
 52
 53q = p; 
 54
 55} 
 56
 57p++; 
 58
 59if  ( p &gt;= limit ) 
 60
 61{ 
 62
 63break  ; 
 64
 65} 
 66
 67if  ( buffer[p] &gt;= 0x40 &amp;&amp; buffer[p] &lt;= 0x7E 
 68
 69|| buffer[p-1] &gt;= 0xA1 &amp;&amp; buffer[p-1] &lt;= 0xA3 &amp;&amp; buffer[p] &gt;= 0x40 &amp;&amp; buffer[p] &lt;= 0xA0 
 70
 71|| buffer[p-1] &gt;= 0xA4 &amp;&amp; buffer[p-1] &lt;= 0xA9 
 72
 73|| ( buffer[p-1] &gt;= 0xAA &amp;&amp; buffer[p-1] &lt;= 0xAF || buffer[p-1] &gt;= 0xF8 &amp;&amp; buffer[p-1] &lt;= 0xFD ) &amp;&amp; buffer[p] &gt;= 0xA1 &amp;&amp; buffer[p] &lt;= 0xFE ) 
 74
 75{  //  很可能是  BIG5  ,由此可以推断,这相邻的汉字串都可能是  BIG5 
 76
 77maybeBig =  true  ; 
 78
 79} 
 80
 81if  ( buffer[p] &gt;= 0x7F &amp;&amp; buffer[p] &lt;= 0xA0 
 82
 83|| buffer[p-1] &gt;= 0x81 &amp;&amp; buffer[p-1] &lt;= 0xA0 
 84
 85|| buffer[p-1] == 0xC6 &amp;&amp; buffer[p] &gt;= 0x7F &amp;&amp; buffer[p] &lt;= 0x0FE 
 86
 87|| buffer[p-1] &gt;= 0xC7 &amp;&amp; buffer[p-1] &lt;= 0xC8 
 88
 89|| buffer[p-1] == 0xF9 &amp;&amp; buffer[p] &gt;= 0xDC 
 90
 91|| buffer[p-1] &gt;= 0xFA ) 
 92
 93{  //  肯定不是  BIG  ,因为在此区间,  BIG  为空 
 94
 95notBig =  true  ; 
 96
 97maybeBig =  false  ; 
 98
 99} 
100
101} 
102
103else 
104
105{  //  非汉字 
106
107if  ( isChinese ) 
108
109{  //  此前是汉字,先输出 
110
111if  ( maybeBig &amp;&amp; !notBig) 
112
113{ 
114
115WriteBIG(buffer,q,p-1-q+1);/  /  待处理的流是  BIG5 
116
117} 
118
119else 
120
121{  //  不肯定是繁体 
122
123WriteGB2BIG(buffer,q,p-1-q+1);  //  &lt;span style="COLOR: green; FONT-FAMILY: 宋体; mso-ascii-font-family: "Times New Roman"</str.length;i++>
Published At
Categories with Web编程
Tagged with
comments powered by Disqus