Python中文排序

Python比较字符串大小时,根据的是ord函数得到的编码值。基于它的排序函数sort可以很容易为数字和英文字母排序,因为它们在编码表中就是顺序排列的。

但要很处理中文就没那么容易了。中文通常有拼音和笔画两种排序方式,在最常用中文标准字符集GB2312中,3755个一级中文汉字是按照拼音序进行编码的,而3008个二级汉字则是按部首笔画排列,

出现这样的结果是因为‘曙’和‘曾’都是常用字,而‘鲑’和‘怡’都是次常用字,但无论从笔画还是拼音来看,这两对顺序都应该反过来。后来扩充的GBK和GB18030编码为了向下兼容,都没有更改之前的汉字顺序,于是sort之后的次序就很乱了。

另一方面unicode编码的中文是按《康熙字典》的偏旁部首和笔画数来排列的,所以排序结果和GB编码又不一样。

的输出是:”佘孙李赵钱”;而保存成gb2312编码后

输出是:“李钱孙赵佘”。显然,这两个结果都不是我们想要的。那我们究竟怎样才能对中文正确排序呢?

先要弄清楚中文词典的排序规则:先按拼音排列,区分四声,拼音相同的就看笔画数目多少,笔画数也相同的再按笔顺中的具体笔划类型来区分,新华字典采用的顺序是一丨丿丶乙,也称作“天上人间”,应该没有笔划类型也完全一样的。所以中文排序不仅需要带音调的汉字拼音对照表,还需要有具体笔顺的数据。

本以为有现成的模块,试了几个都不理想。pyzh的转换代码只支持不到7千字,而且还没有音调。水木的roy的代码涵盖了2万多字符,但需要pysqlite支持……还是自立更生吧~

我找到最全的数据是slowwind9999上传到csdn的unicode汉字编码表,包括全部20902个汉字的全拼、五笔、郑码、UNICODE、GBK、笔画数 部首,以及笔顺编号(拼音部分没有音调,而且个别注音有误,如 囍,猤,啹等字,使用需注意。)我提取了其中的笔顺数据,又用江志键的“实用汉字转拼音”程序制作了unicode汉字音调版,其中中文汉字用四声标注,319个日韩汉字没有音调以示区别,并根据汉典的数据略作修正(但仍可能存在错误)。有了这两个对照表,下面的工作就简单了。

笔顺字典的处理方法也完全相同,虽然文本有两万行,导入还是很快的,0.5秒左右。如果把这两个文件合并起来统一处理,应该可以更快。

查找中文,一律转为UTF8字符串,汉字外的其他字符不做处理,原样输出。如果需要声母,只输出拼音的第一个字符就是了。只要资料准确,比较起来就很轻松了。数字在字母之前,爱(ai4)便会比昂(ang2)靠前,而笔顺值的位数代表了笔画数,数值对应笔划权重,直接比较数字大小就可以得到正确的顺序。代码如下:

现在我们就可以按照字典的规范给中文排序了。

终于得到了“李钱佘孙赵”,样例文件点此下载
这里我没有考虑多音字的情况。如果想让程序自动识别,可以增加多音词组对照表,通过上下文来判断。我不知道哪里有这样的数据,反正对于多音字不太多的情形,手动调整也就够了。

订阅评论
提醒

19 评论
最旧
最新 最多投票
内联反馈
查看所有评论
Angell
2009 年 12 月 29 日 14:40

你的python用的是什么编辑器啊?

2010 年 1 月 3 日 16:10

好文章,谢谢!
转载了

2010 年 1 月 4 日 20:54

恩,这个思路很有意思,前段我做了个汉字字符串的比较和编辑距离计算的程序,也考虑过从unihan.txt来获得数据信息
另:按行读取文件我习惯lines = open(filename, ‘r’).readlines()
排序可以直接调用python内置的sort函数,把自定义的comp传进去就可以了

GaoXiong
回复给  Yurii
2017 年 11 月 24 日 15:04

好文 + 好分享

livepine
2010 年 1 月 7 日 05:37

谢谢楼主的分享。不过你说“笔画数也相同的再按笔顺中的具体笔划类型来区分”,不知为什么代码里没实现?在 slowwind9999 的 unicode 汉字编码表中是有这个部分的,提取出来加上两行代码就行了。

livepine
回复给  gerry
2010 年 1 月 9 日 07:05

嗯,确实是,没仔细看 bh.txt。不过 bh 这个名字让我以为还是笔画呢 :-)

Helen Wang
2010 年 1 月 10 日 19:21

久仰大名,未尝得见,我也来自油田,现在在意大利工作,等闲上下QQ啦~~~