Python简繁转换

简繁转换的工具很多,但始终没有一个完美的解决方案。由于字符之间从来都不是简单的一一对应,不仅一简对多繁的情况大量存在,多简对一繁也屡见不鲜。情况的复杂性由下面几例可见一斑:

头发发展 -> 頭髮發展
萝卜卜卦 -> 蘿蔔卜卦
秒表表达 -> 秒錶表達
晾干乾坤 -> 晾乾乾坤

要正确完成这样的转换,就要在单字对应关系之外加上词组对应。这一点无论Google 翻译,MS Word 或者ConvertZ 基本都可以做到(虚词部分可能稍微困难些)。但两岸相差的不只是字形,还有名称叫法。这一点嘻来嚷往最早的一篇文章中讲的很清楚。转引一个例子:“大衛碧咸在寮國見到了布希”。我第一次看到时完全不知所谓,虽然认得每一个字,还是猜不到这就是“大卫·贝克汉姆在老挝见到了布什”的香港版。要想正确转换这样的句子,就要建立更广泛的简繁词组对照表。也许你会觉得这已经超出了字体转换的范畴,开始接近自动翻译了。但从技术的角度上讲,把“软件”对应为“軟件”,”軟體” 或者 “ruan jian”并没有什么不同,前提是要有一个完善的转换语料库。当然这个前提并不容易满足,因为“所有的规则都有例外“。

我不知道语言学中的例外是否真的有限,但至少我们可以把已知的都记下来。在Word或者ConvertZ之类的软件中无法修订转换规则;在 google 翻译中虽然可以提交修改建议,但缺乏及时有效的反馈;幸好有一个转换系统是开放的——维基百科(以下内容感谢菲菇指点)。

为了满足大陆、台湾、香港、新加坡和马来西亚等不同地区中文用户的需求,在ZhengZhu等维基人的努力下,維基百科自2004年底开始逐步发展出一套比较成熟的简繁转换方案。分别记录简繁字体的对应关系和不同地区的用词习惯。这个办法的实用性已在现有30万中文维基条目的应用中得到验证。中文维基目前正在使用的内置简繁转换表地址在这里:

http://svn.wikimedia.org/svnroot/mediawiki/trunk/phase3/includes/ZhConversion.php

这个php文件包含了$zh2Hant、$zh2Hans、$zh2CN、$zh2HK、$zh2TW、$zh2SG这6个数组,分别对应中文->繁体、中文->简体、中文->大陆用词、中文->香港用词、中文->台湾用词和中文->新加坡用词的转换规则。例如从大陆简体到台灣正體的转换就是先将中文(允许简繁混用)转为繁体,再替换其中的台湾用词。如果不涉及复杂长句的简单应用,实现起来十分容易,将对应关系读入字典,用最大正向匹配算法查找词组替换就好。下面是 python 代码:

输出结果如下:

头发发展萝卜卜卦秒表表达 < -> 頭髮發展蘿蔔卜卦秒錶表達
大卫·贝克汉姆在老挝见到了布什 < -> 大衛碧咸在老撾見到了布殊
大衛碧咸在寮國見到了布希 < -> 大卫·贝克汉姆在老挝见到了布什

这段代码只是为了举例,没有加入对标点段落的处理,如果直接用于较长的句子甚至段落效率会很低。好在有现成的工具。菲菇为维基写的字词转换器放在这里,不过使用了C扩展,我没有测试。PythonCN的Xie Yanbo 也放出过一个基于状态机的纯Python版本langconv,效果也不错。只是要做个接口,把最新的转换表存成它需要的格式。

由于语言本身的复杂性, 需要改进的地方仍然很多. 例如最大正向匹配算法就远非完美,在“张必须发皆白”或者”人体内存在很多微生物”这样的句子中就会错误转换”必须”和”内存”。如果希望程序能自动处理这种复杂情况就需要引入难度更大的中文分词技术, 目前维基在这种地方主要还是人工调整。另外要注意维基的转换表是针对正向最大匹配算法设计的,使用其他的算法可能会导致一些意外的转换错误。这时候用开放代码的好处就显现出来了. 如果在使用中发现了例外,可以直接编辑本地转换规则,不用等待软件更新系统升级. 同时也请随手在维基的这个页面提交新的字词转换规则请求,让这个系统更完善。毕竟,开源系统是我们能自由获取的最好选择。

订阅评论
提醒

10 评论
最旧
最新 最多投票
内联反馈
查看所有评论
2010 年 9 月 17 日 22:37

[…] From here: http://gerry.lamost.org/blog/?p=603 […]

2010 年 10 月 12 日 15:15

very Good.
熙来攘往那篇文章很久之前看过,不过那里没有提供脚本。
感谢博主的脚本,哇咔咔,省时省力啊~

2012 年 4 月 3 日 03:57

受益匪浅,万分感谢!

enyou
2012 年 10 月 15 日 21:49

最近在在做关于wiki的简繁体转换。看了你的文章,收获很大。非常感谢。

2012 年 12 月 12 日 16:31

根本不用自己实现最大字符串匹配,直接用string.replace(‘aa’, ‘bb’)就行了。