`
yangshen998
  • 浏览: 1288830 次
文章分类
社区版块
存档分类
最新评论

让你的软件支持繁体中文

 
阅读更多

让你的软件支持繁体中文

中国台湾、香港的汉字用的是BIG5编码,而大陆的汉字用的是GB编码(GB2312也好,GBK也好),简体中文软件直接拿到繁体中文环境下运行,问题就出来了。

怎么办呢?

我们的软件是一款用C#.NET+ASP.NET开发的,所谓B/S型的软件,客户端只须用浏览器访问我们的服务器就行了。很自然的就想到,把代码中的所有的简体字都转换成繁体字,问题不就解决了吗?

说干就干。从网上找来了一款转换工具将全部代码文件转换了一遍。编译后运行,发觉静态的文字或提示信息确实已经变成了繁体,但从数据库中拿出来的还是简体(乱码),转换后的各种配置文件也读取出错(因为程序仍然按GB编码的格式进行读取)。还有一个问题,就是源代码只能转换一次。因为第一次转换后GB变成了BIG5,如果再转,就是BIG5BIG5,结果变得不可辨认。由于源文件非常多,修改维护起来非常麻烦。

看来这种方法不可行。

那么能不能给我们的软件加上自适应的功能,增加对繁体中文的支持呢?

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<str.Length;i++ )

{

//_SGB是部分GB2312简体中文字库,_tGB则是对应的GB2312繁体字库

int j = _sGB.IndexOf(str[i]);

if( j != -1 )

{

str = str.Replace(_sGB[j],_tGB[j]);

}

}

//950BIG5码代码页编号

e = Encoding.GetEncoding(950);

_sink.Write(e.GetBytes(str),0,e.GetByteCount(str));

}

……

}

这样写,是建立在待转换的流全部都是GB编码的基础上的,而大多数情况下也没有什么问题,不过,如果一个页面存在表单控件且控件内有汉字内容随同输出时,那么该页面在运行过程中有回传等刷新动作的话,就可能出现乱码。究其原因,是因为在页面第一次打开时,控件值由简体转成了繁体,回传的时候,则传回服务器的这部分控件值也为繁体。接着再输出,问题就来了:控件值为繁体,而页面本身还是简体,也就是说,输出流中存在混合编码,这样还一刀切将它们认为全是GB编码来加以转换就不行了,要加以区别。

怎么区别呢?BIG5GB有什么区别吗?很遗憾,并没有什么明显的区别,也就是说,给你一个汉字编码,很难判断它究竟是GB还是BIG5。一般倾向于认为低字节在0x40~0x7F范围的就是BIG5码,因为没有简体字的低字节在这个范围。不过要注意,GB编码也有繁体字,并且这些繁体字的低字节也有位于0x40~0x7F的。所以这招并非万灵丹。

将数值从高字节0x81~0xFF,低字节0x40~0xFF这样组合输出到页面,如下:

string str = "";

Encoding gbe = Encoding.GetEncoding(936);

byte[] buffer = {0,0};

for( byte y = 0x81;y<0xFF;y++ )

{//高字节

str += "<br>";

for( byte x = 0x40;x<0xFF;x++ )

{//低字节

buffer[0] = y;

buffer[1] = x;

//以红色输出汉字,并注明其高低字节值

str += "&nbsp;0x" + y.ToString("X") + x.ToString("X") + "<font color=/"red/" size=4>" + gbe.GetString(buffer) + "</font>";

}

}

Response.Write(str);

然后在浏览器里分别用GB编码和BIG5编码观察,你会发现,这两种编码中,都存在着有些字节值并没有相应的汉字,而是一些奇怪的符号、问号甚至是空白。于是可以这样认为:如果一个汉字的字节值在某种编码中找不到汉字,则说明它不属于这种编码。经过认真比较归纳,两种编码都划定了一些范围,然后可以逐个考察输出流中的汉字,看它是否落在该范围,以此判定它属于何种编码。

虽然划定了一些范围,但GBBIG5重叠的区域实在太多,有许多字用两种编码去套,好象都可以,逐个字转换,误差很大。后来发现了一个很重要的思想,就是:在混合汉字编码的流中,不同的汉字编码总是不相邻的,它们中间有西文字符隔开(因为网页中,控件值都包含在许多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;

//这里定义了两个看似互相矛盾的布尔量:maybeBignotBig,主要是让它们配合使用。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);

}

}

//处理对象为GB

private void WriteGB2BIG(byte[] buffer, int offset, int count){……}

//处理对象为BIG5

private void WriteBIG(byte[] buffer, int offset, int count){……}

//处理对象为ASCII

private void WriteAscii(byte[] buffer, int offset, int count){……}

……

}

应用修正过的类后,浏览器用BIG5编码浏览运行我们的软件,效果令人非常满意,几乎看不到什么乱码,已经达到了实用的效果。不过繁简切换是一个相当复杂的问题,并不是仅仅是简单地将简体字转换成繁体字就行了,有时还涉及到语义的问题。比如,简体中文中,不论“发展”的“发”还是“头发”的“发”都是同一个字,而在繁体中,它们是不同的两个字。这部分已经超出了笔者现有的水平,不在考虑之列了。

分享到:
评论

相关推荐

    毕业设计&课程设计&毕设&课设-java-酒店管理系统

    项目均经过测试,可正常运行! 环境说明: 开发语言:java JDK版本:jdk1.8 框架:springboot 数据库:mysql 5.7/8 数据库工具:navicat 开发软件:eclipse/idea

    毕业设计&课程设计&毕设&课设-java-ssm文物管理系统

    项目均经过测试,可正常运行! 环境说明: 开发语言:java JDK版本:jdk1.8 框架:springboot 数据库:mysql 5.7/8 数据库工具:navicat 开发软件:eclipse/idea

    vb图书管理系统设计(源代码+论文).rar

    1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。

    什么是 Scratch 编程中的 Iteration?

    什么是 Scratch 编程中的 Iteration? Scratch 是一种高级可视化编程语言工具,它通过内置程序基础知识的图表和块与用户交互。Scratch 用于制作交互式程序,特别是对于使用块式界面的孩子,这样他们就可以轻松学习语言并且可以免费使用。在本文中,我们将讨论 scratch 中存在的 iteration block。 Scratch 迭代块 迭代是允许重复命令或一组行的概念。它在计算机编程语言中也称为循环。当代码执行(重复)一次时,这种重复称为一次迭代。Iteration control 块基本上通过将相似任务分组到一个块中来减少要执行的类似任务的数量。在 Scratch 中,控制块包含迭代工具,如下图所示:

    基于PHP语言的校园报修系统-crs.mjc.com-master.zip

    基于PHP语言的校园报修系统-crs.mjc.com-master.zip

    Java集合面试题详解-从数据结构到HashMap源码剖析

    内容概要:该文详细解释了Java集合面试题的重要考点,包括三大模块内容:数据结构简介、集合相关面试题及其解析、真实面试还原场景。其中重点介绍了Java中最常见的几种数据结构如数组、链表、栈和队列、散列表以及二叉树。随后,文中详细分析了Java常用集合类ArrayList、LinkedList、HashMap的工作原理及时空复杂度;并对面试题进行了详细的解析和演示。真实面试还原模块则生动模拟面试过程,以帮助求职者熟悉面试问答环节,提高实战能力。 适合人群:正在积极准备Java面试或希望加强理解的中高级程序员,尤其是在集合和数据结构方面有所欠缺的开发人员。 使用场景及目标:该文章旨在辅助求职者应对技术面试时关于集合的问题挑战,帮助他们更好地掌握内部实现机制及应用技巧,同时为现有开发工作中涉及的相关问题提供理论指导。 其他说明:阅读者可以根据自己的实际情况挑选感兴趣的部分仔细研读,特别是在面对实际编码任务或是准备特定公司招聘考试时尤为有用。

    毕业设计&amp;课程设计&amp;毕设&amp;课设-java-东理咨询交流论坛

    项目均经过测试,可正常运行! 环境说明: 开发语言:java JDK版本:jdk1.8 框架:springboot 数据库:mysql 5.7/8 数据库工具:navicat 开发软件:eclipse/idea

    "Abaqus蠕变裂纹模拟:子程序开发与案例分析",abaqus蠕变裂纹等子程序或者案例 ,Abaqus; 蠕变; 裂纹; 等子程序; 案例,"Abaqus蠕变裂纹:等子程序与案例分析"

    "Abaqus蠕变裂纹模拟:子程序开发与案例分析",abaqus蠕变裂纹等子程序或者案例 ,Abaqus; 蠕变; 裂纹; 等子程序; 案例,"Abaqus蠕变裂纹:等子程序与案例分析"

    VB网吧计费系统设计(论文+源代码).rar

    1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。

    机器学习算法在裂缝扩展预测中的应用研究,机器学习预测裂缝扩展 ,机器学习; 裂缝扩展; 预测模型; 数据处理; 扩展监测,机器学习预测裂缝扩展的智能模型研究

    机器学习算法在裂缝扩展预测中的应用研究,机器学习预测裂缝扩展 ,机器学习; 裂缝扩展; 预测模型; 数据处理; 扩展监测,机器学习预测裂缝扩展的智能模型研究

    Java编程全面指南:核心技术详解及项目实战应用

    内容概要:本文是一份详尽的 Java 教程,涵盖了 Java 编程语言的基础语法与高级特性的各个知识点。首先讲解了基本的数据类型、运算符、控制结构等基础内容;接着深入探讨面向对象编程的相关概念如类和对象的操作、访问控制、异常处理以及泛型和多线程编程等;还介绍了 I/O 流与文件系统的处理,Web 和企业级应用程序(Java EE)的技术堆栈;最后给出了几个具体的应用案例与项目示例,让读者能通过实例更好地理解和巩固所学到的知识点。每个章节的内容都十分紧凑并且具有连贯性。 适合人群:适合于有一定编程基础但缺乏系统性指导的新手开发者或者想要深入了解Java的企业程序员。 使用场景及目标:帮助用户掌握从零开始构建实际 Java 工程的能力,比如创建学生信息系统或开发网络聊天室这样的小型软件作品,进而提升其解决复杂业务逻辑难题的实力。 阅读建议:随着每章提供的完整示例不断实践编码练习,有助于消化理解关键概念及其背后的思想;同时关注项目实例中的设计思路,在动手实验里加深对整个知识框架的理解程度。

    基于多特征输入的Bayes-SVM数据分类预测模型:迭代优化与混淆矩阵图分析,bayes-SVM贝叶斯优化支持向量机的数据分类预测,bayes-SVM分类预测,多特征输入模型 多特征输入单输出的二分

    基于多特征输入的Bayes-SVM数据分类预测模型:迭代优化与混淆矩阵图分析,bayes-SVM贝叶斯优化支持向量机的数据分类预测,bayes-SVM分类预测,多特征输入模型。 多特征输入单输出的二分类及多分类模型。 内注释详细替数据就可以用,迭代优化图,混淆矩阵图。 ,贝叶斯-SVM; 贝叶斯优化; 支持向量机; 多特征输入; 数据分类预测; 二分类模型; 多分类模型; 迭代优化图; 混淆矩阵图,"Bayes-SVM模型:多特征输入支持向量机数据分类预测与迭代优化"

    如何在 Keil Microvision 中执行汇编语言程序?

    如何在 Keil Microvision 中执行汇编语言程序?

    JAVA 最新最全面试题

    本文作者结合10年大厂面试官经验,整理了Java技术面试中的7大核心领域、58个高频问题,涵盖从基础到进阶的全方位知识点解析。

    (源码)基于STC15F104W和TSIC506的温度传感器测试系统.zip

    # 基于STC15F104W和TSIC506的温度传感器测试系统 ## 项目简介 本项目是一个基于STC15F104W微控制器和TSIC506温度传感器的测试系统。通过该系统,用户可以测试和监控TSIC506温度传感器的性能和输出数据。 ## 项目的主要特性和功能 微控制器使用STC15F104W微控制器作为主控芯片。 温度传感器集成TSIC506温度传感器,用于精确测量环境温度。 硬件设计包含详细的原理图和传感器数据手册,方便用户理解和使用。 ## 安装使用步骤 1. 下载源码用户已经下载了本项目的源码文件。 2. 硬件连接按照原理图将STC15F104W微控制器与TSIC506传感器正确连接。 3. 编译代码使用相应的开发工具(如Keil等)编译项目代码。 4. 烧录程序将编译后的程序烧录到STC15F104W微控制器中。 5. 运行测试启动系统,观察并记录TSIC506传感器的温度输出数据。

    PyTorch 卷积神经网络与计算机视觉

    PyTorch 卷积神经网络与计算机视觉

    NGBoost集成模型及其Shap方法在回归任务中的应用:一种2019年斯坦福吴恩达团队提出的新方法,自带数据集,可直接运行并采用Shap分析进行模型解读的Python代码实践,NGBoost-sha

    NGBoost集成模型及其Shap方法在回归任务中的应用:一种2019年斯坦福吴恩达团队提出的新方法,自带数据集,可直接运行并采用Shap分析进行模型解读的Python代码实践,NGBoost-shap方法回归任务,由斯坦福吴恩达团队提出,属于集成模型的一种2019年提出的,算是比较新的方法了 自带数据集,可以直接运行,对模型采用shap进行分析,所有图所见即所得 python 代码 ,NGBoost; shap方法; 回归任务; 斯坦福吴恩达团队; 集成模型; 2019年提出; 自带数据集; Python代码,NGBoost-shap方法:集成模型新思路的回归任务解决方案

    "深入解析Informed RRT*算法:内涵与详细代码注释解析",informed rrt*算法 内涵详细的代码注释 ,informed-rrt-algorithm; 详细代码注释,基于info

    "深入解析Informed RRT*算法:内涵与详细代码注释解析",informed rrt*算法 内涵详细的代码注释 ,informed_rrt_algorithm; 详细代码注释,《基于informed rrt*算法的详细代码注释》

    vb企业人事管理信息系统设计与实现(源代码+论文).rar

    1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。

    显微镜下的细菌高清图像分割的数据集

    显微镜下的细菌高清图像分割的数据集

Global site tag (gtag.js) - Google Analytics