最近在找,简体与繁体之间转换时,发现一个写得不错的博客: http://www.codeproject.com/KB/webservices/Chinese_Style_Converter.aspx . 如果大家有需要的话,强烈要求到原创那个网页浏览.在这里只是做一个转载.
把作者的一些内容贴出来:
大家都知道中文有繁体和简体两种格式,而且也存在着很多的免费或者负费软件提供在它们之间转换的功能,甚至还有提供在Windows 98下同屏幕显示两种字体的软件。而微软也在这个方面下了不少的努力,Microsoft Word就是其中一个例子。从Visual Basic 6开始就已经提供了这个功能,现在连.net framework也有了这个免费的功能了,而且还是免费的(.net framework distributed本身是免费的,只要使用免费的语言编译软件编译组件就可以享用它了)。
下面就让我们来看看如何在.net framework中进行中文繁简转换,并且也顺带关心一下关于Encoding(编码)的转换。最后由于我们正处于面向服务的编程时代,所以我将会把这个功能做成以几种形式存在的服务以及讨论如何做这些服务的部署。
l 繁简转换
微软提供的这个功能在Microsoft.VisualBasic.Strings.StrConv中,十分容易地就可以调用它,下面是一个简单的将简体转为繁体的例子:
using Microsoft.VisualBasic;
……
string source = “中国是一个美丽的国家。”;
string target = Strings.StrConv(source, VbStrConv.TraditionalChinese, 0);
然后我们就得到了内容为:“中國是一個美麗的國家。”的字符串target。如果想将繁体转为简体,只需要将第2个参数改为VBStrConv.SimplifiedChinese就可以了。
当然这个调用简单的函数还有其他强大的功能,比如提供日文平假名和片假名的转换等。我建议读者一定要抽时间读一下MSDN中关于此功能的介绍。
l Encoding(编码)转换
这个世界有很多不同的文字,当被影射为数字格式的时候,由于各个国家所采用的编码方式的不同,导致相同的2进制数字可能在不同的编码方式中代表着不同的内容。GB2312和Big5就是我们所知道的典型的例子。
Unicode的出现就是为了尽可能地将所有文字都揽括其中(当然,仍然有一部分文字未能包括,比如3级汉字的某些部分就没有被包括)。但这么多的编码方式导致相同的汉字在不同码制下的2进制数字是几乎完全不同的,从下面的表格可以看到:
|
中 |
国 |
是 |
一 |
个 |
美 |
丽 |
的 |
国 |
家 |
936 |
D6D0 |
B9FA |
CAC7 |
D2BB |
B8F6 |
C3C0 |
C0F6 |
B5C4 |
B9FA |
BCD2 |
UTF-8 |
E4B8AD |
E59BBD |
E698AF |
E4B880 |
E4B8AA |
E7BE8E |
E4B8BD |
E79A84 |
E59BBD |
E5AEB6 |
UTF-16 |
2D4E |
FD56 |
2F66 |
004E |
2A4E |
8E7F |
3D4E |
8476 |
FD56 |
B65B |
|
中 |
國 |
是 |
一 |
個 |
美 |
麗 |
的 |
國 |
家 |
936 |
D6D0 |
87F8 |
CAC7 |
D2BB |
8280 |
C3C0 |
FB90 |
B5C4 |
87F8 |
BCD2 |
950 |
A4A4 |
B0EA |
AC4F |
A440 |
ADD3 |
ACFC |
C452 |
AABA |
B0EA |
AE61 |
UTF-8 |
E4B8AD |
E59C8B |
E698AF |
E4B880 |
E5808B |
E7BE8E |
E9BA97 |
E79A84 |
E59C8B |
E5AEB6 |
UTF-16 |
2D4E |
0B57 |
2F66 |
004E |
0B50 |
8E7F |
979E |
8476 |
0B57 |
B65B |
在接触.net framework前,在使用VB6的年代,我是使用ADO.Stream的CopyTo方法来进行编码转换的(因为我只略懂C,更别说C++或者MFC了),当然将GB转换成UTF-8的时候还需要自己在字节数组中每两个字节插入一个零字节(对于英文字符),十分弱智。在使用Java后,觉得进行这样的转换十分轻松。现在使用.net framework也一样的方便。
.net framework中,进行编码转换的是System.Text.Encoding.Convert的方法,调用方法为:System.Text.Encoding.Convert(Encoding source, Encoding target, byte[] source Bytes)(这个方法存在过载的定义,请阅读MSDN以获得更多的信息)。下面是一个简单的例子:
using System.Text;
……
byte[] source = Encoding.Unicode.GetBytes(“中国是一个美丽的国家”);
byte[] target = Encoding.Convert(Encoding.Unicode, Encoding.UTF8, source);
那么我们就得到了编码为UTF-8格式的字节数组target。
好了,谋杀了一页多A4纸后,开始到了将上面所说的糅合在一起的时候了。
l 将繁简和编码转换合在一起
我建立了一个叫Converter的类,并且希望可以通过调用其中的一个方法就可以同时实现两种转换。另外由于被转换的中文可能会以多中形式存在(字符串、字节数组、流甚至文件),所以我也希望可以通过方法过载的方式让不同形式的中文可以转换到多种形式去。当看到这里,估计你会知道这会是一个多对多的影射关系。
为节省篇幅,我不打算复制所有的代码,所以仍然使用英文版说明中的程序截图来让你可以有一个大致的印象:
其中进行转换的核心代码的为:
可以看到,我先进行繁简体的转换,然后再进行繁体结果的转换修正(下面的章节中会提及),最后再将为Unicode编码的中间结果转换成想要的目标编码。
l 繁体转换结果的修正
繁体就是有点古怪(否则就不叫繁了),同样的汉字,不同的搭配场合,样子就是不一样。很多软件都考虑了这方面的问题,比如Microsoft Word。大致做法都是枚举所有与字级别的转换后结果不符合搭配的场合的话,再将这些内容进行替换。大家可以看看下面的这个搭配的例子:
Simplified Chinese |
Traditional Chinese |
头发 |
頭髮 |
发达 |
發達 |
注意 |
注意 |
备注 |
備註 |
繁体的繁可见一斑。我打算使用类似的解决办法,将要替换的内容放到XML文件中,然后读入内存,以提供转换使用。为避免单字转换覆盖词转换,词转换覆盖句子转换的情形,我使用了System.Data.DataTable来存放这些内容,并按照它们的长度进行从小到大的排序。另外,为处理词组中包含空格的问题,比如:“头发”和“头 发”其实有可能是由于要调整空位而估计加空格,所以在检测和进行内容替换的时候,还需要考虑中间可能有空格的情况:
另外由于我们可能会不断地完善自己的繁简转换调整XML文件,而当这个功能变成服务的时候,总不可能停下这个服务来让它得到内容的更新吧?所以我就建立了一个提供设置信息的类,这个类使用FileWatcher来监视在公共属性中制定的的XML文件,一旦文件被修改,它将会在再次调用转换功能的时候将这个XML文件的内容重新装载。
还有,值得一提的是,我们还可以用这个功能来进行一些词语方面不同的转换,例如:字节 vs. 位元, 图标 vs. 圖示,窗口 vs. 視窗等。
l 做一个调用Converter类的工具
做完Converter类后,我想通过做一个调用它的简单工具来作为示范的例子。当然这个简单的工具自然是有一定使用价值的啦。
我建立了一个WinForm的程序来调用Converter类,另外由于需要对下面提及的服务进行示例,我使用了可以在config文件中定义调用本地组件、Web Service和.net remoting 3种调用形式的做法。在建立WinForm程序之前,我先建立一个WinForm Control来实现所有的功能,然后才将此控件放到一个WinForm中,之所以这样做,是因为我还希望可以在IE中,通过实现ActiveX控件(确切地说是类似Java Applet)的方式来在网页中可以使用这个转换的功能。
核心的类已经做好,下面让我们来看看如何把它变成一个服务,让其他计算机来调用。做成服务的魅力就是其他计算机可以不需要安装这个组件,仅需要通过固定的接口来调用就可以享受到这个功能。并且服务由于是基于接口来提供的,所以享受服务的可以是用各种不同语言来编写的客户端。而且在更新的时候只需要考虑做单点维护就可以了。好啦,欢迎来到面向服务的年代。
l COM+ Application
Java和.net横行的年代,大家都冲着更新、更美好的事物去了,但谁来关心那些已经写好并且在过去的几年,甚至今后一年内仍然是稳固地提供服务的基于COM/DCOM的应用程序呢?答案是:还是我们这些做软件的。在未来得及把所有软件重写一遍的时候,想不想旧的应用程序,或者新的但却仍然使用COM/DCOM的程序也能享受到中文繁简和编码转换的好处呢?
我当然想,所以第一个要做的服务就是将Converter类封装到COM+ Application中。遵从MSDN的指引,写一个包装Converter的继承System.EnterpriseServices.ServicedComponent的类,是十分容易的。当然要小心,为了同时提供早绑定和晚绑定,并且还需要防止每次做注册时都会自动生成新的GUID,还有为避免在以后修改接口的时候会在COM+ Application中留下对COM来说会冲突的问题,我们需要定义固定的GUID,并且先写好Interface的定义,最后还需要在自己的新类里实现所定义的Interface和使用[ClassInterface(ClassInterfaceType.None)]的属性。
部署这个写好的类可以有3种常用的方法:
1. 让程序第一次调用的时候让.net framework帮忙建立COM+ Application
2. 使用Regsvcs.exe建立COM+ Application
3. 使用Installer类来自定义注册的行为,然后通过Regsvcs.exe或者Windows Installer来建立COM+ Application
我是一个很懒惰的人,当然希望什么事都自动做好是最方便的。第一种方法虽然舒服和潇洒,但却需要第一个调用的人拥有服务器本地管理员权限才可以;但现实生活中,一般用户总不会拥有服务器的管理员权限,那么这个差事还是一样要落到自己或者管理员的手上。既然至少都要干点什么,那么就还是不要太懒惰吧。第二种方法方便,但要自己输入命令或者至少先建立个快捷方式啊。第三种看起来比较专业,安装和卸载起来也方便(交给Windows Installer就可以啦),而且还可以定义其他的行为。
那么就用第三种方式吧。
按照MSDN的指引,编写一个Installer类,分别重载Install和Uninstall事件就可以了(其他的交给Windows Installer就是啦):
然后我们甚至可以通过Windows Host Script来调用它(当然实现要在客户端做类的注册,请阅读MSDN中相关的内容):
dim objConverter
set objConverter = createobject("ChineseUtilComPlus.ConverterService", “MyServer”)
msgbox objConverter.StringToStringEncodingIntegerFormat("中国是一个美丽的国家", 2, 936, 65001, 936)
set objConverter = nothing
l .net remoting
DCOM的升级版本就是.net remoting,虽然Web Service流行,但.net remoting仍然是在速度和便利方面上来说的利器。通常我们会在IIS或者Windows Service中提供.net remoting的服务。我打算在Windows Service中提供Converter类的服务。
编写一个继承System.ServiceProcess.ServiceBase的封装Converter类的类后,还需要在config文件中加入支持指定中文繁简转换替换的XML文件的定义,另外还加入了定义这个服务是通过http和tcp来提供调用的定义:
然后,当然还是再做一个帮助部署的Installer类啦(其他的让Windows Installer去管好了):
l Web Service
Web Service的好处就是可以让使用SOAP的应用程序可以调用,其中的魅力和前景就不再多说了。
但在建立Web Service之前,我们需要做一些取舍:System.Text.Encoding和Stream都不能直接做XML序列化,而且因为懒,我也不打算做。所以就提供使用int和string类型来定义System.Text.Encoding的方法,然后通过System.Text.Encoding.GetEncoding的功能来取得System.Text.Encoding。另外也放弃了对Stream转换的支持。最后,由于安全因素的考虑,还放弃了对文件转换的支持。
最后,我只针对字节数组和字符串的转换做了封装。当然,也少不了在web.config里提供定义中文繁简转换替换的XML文件支持。
l 部署
只要遵照MSDN的指引,建立服务不难。但如果要用Visual Studio.net 2003来建立Windows Installer安装包,我发现在MSDN里可以获得的资源却是少得可怜。
我需要花更多的时间来弄明白如何可以用Visual Studio.net 2003来建立可以让用户选择性部署所有或者部分服务的Windows Installer安装包。最后,我决定将针对每个服务都先做一个Merge Module,然后再使用一个Setup Package来包括所有的Merge Module,最后再定义一些选择的界面。还有通过和选择相对应的自定义属性来控制哪个服务将会被安装。
当然使用其他的安装包软件也是很容易的,象Wise Installer for Windows Installer等。
l 其他可以做的?
当然还有其他值得完善的方面,我们其实还可以
1. 让用户选择.net remoting是同时支持http和tcp,还是其中之一?
2. 还有可以让用户输入使用什么端口来提供服务
3. 对Converter类提供异步的转换功能
4. 对Converter加入对整个目录的符合条件的文件做批量转换的功能
5. 还有更多的,只要想得到就是了
我没有把太多的代码放上来(因为实在是太简单了),但仍然希望如果你有空的话,可以粗略浏览一番。中文繁简转换是一个很简单的功能,但其实我们可以按照这样的思想,把更多有用的功能变成服务,然后让更多的程序来尽情享用。
尽情享受中文繁简转换吧! :-P