本文實(shí)例講述了Python實(shí)現(xiàn)針對中文排序的方法。分享給大家供大家參考,具體如下:
Python比較字符串大小時(shí),根據(jù)的是ord函數(shù)得到的編碼值。基于它的排序函數(shù)sort可以很容易為數(shù)字和英文字母排序,因?yàn)樗鼈冊诰幋a表中就是順序排列的。
1
2
|
>> print ',' < '1' < 'A' < 'a' < '阿' True |
但要很處理中文就沒那么容易了。中文通常有拼音和筆畫兩種排序方式,在最常用中文標(biāo)準(zhǔn)字符集GB2312中,3755個(gè)一級中文漢字是按照拼音序進(jìn)行編碼的,而3008個(gè)二級漢字則是按部首筆畫排列,
1
2
|
>> print '曙' < '鮭' , '曾' < '怡' True True |
出現(xiàn)這樣的結(jié)果是因?yàn)?lsquo;曙'和‘曾'都是常用字,而‘鮭'和‘怡'都是次常用字,但無論從筆畫還是拼音來看,這兩對順序都應(yīng)該反過來。后來擴(kuò)充的GBK和GB18030編碼為了向下兼容,都沒有更改之前的漢字順序,于是sort之后的次序就很亂了。
另一方面unicode編碼的中文是按《康熙字典》的偏旁部首和筆畫數(shù)來排列的,所以排序結(jié)果和GB編碼又不一樣。
1
2
3
4
5
|
# encoding=utf8 char = [ '趙' , '錢' , '孫' , '李' , '佘' ] char.sort() for item in char: print item.decode( 'utf-8' ).encode( 'gb2312' ) |
輸出是:"佘孫李趙錢";而保存成gb2312編碼后
1
2
3
4
5
|
# encoding=gb2312 char = [ '趙' , '錢' , '孫' , '李' , '佘' ] char.sort() for item in char: print item |
輸出是:“李錢孫趙佘”。顯然,這兩個(gè)結(jié)果都不是我們想要的。那我們究竟怎樣才能對中文正確排序呢?
先要弄清楚中文詞典的排序規(guī)則:先按拼音排列,區(qū)分四聲,拼音相同的就看筆畫數(shù)目多少,筆畫數(shù)也相同的再按筆順中的具體筆劃類型來區(qū)分,新華字典采用的順序是一丨丿丶乙,也稱作“天上人間”,應(yīng)該沒有筆劃類型也完全一樣的。所以中文排序不僅需要帶音調(diào)的漢字拼音對照表,還需要有具體筆順的數(shù)據(jù)。
本以為有現(xiàn)成的模塊,試了幾個(gè)都不理想。pyzh的轉(zhuǎn)換代碼只支持不到7千字,而且還沒有音調(diào)。水木的roy的代碼涵蓋了2萬多字符,但需要pysqlite支持......還是自立更生吧~
我找到最全的數(shù)據(jù)是slowwind9999上傳到csdn的unicode漢字編碼表(點(diǎn)擊此處本站下載。),包括全部20902個(gè)漢字的全拼、五筆、鄭碼、UNICODE、GBK、筆畫數(shù) 部首,以及筆順編號(拼音部分沒有音調(diào),而且個(gè)別注音有誤,如 囍,猤,啹等字,使用需注意。)我提取了其中的筆順數(shù)據(jù),又用江志鍵的“實(shí)用漢字轉(zhuǎn)拼音”程序制作了unicode漢字音調(diào)版,其中中文漢字用四聲標(biāo)注,319個(gè)日韓漢字沒有音調(diào)以示區(qū)別,并根據(jù)漢典的數(shù)據(jù)略作修正(但仍可能存在錯(cuò)誤)。有了這兩個(gè)對照表,下面的工作就簡單了。
1
2
3
4
5
6
7
8
9
10
|
# 建立拼音辭典 dic_py = dict () f_py = open ( 'py.txt' , 'r' ) content_py = f_py.read() lines_py = content_py.split( '\n' ) n = len (lines_py) for i in range ( 0 ,n - 1 ): word_py, mean_py = lines_py[i].split( '\t' , 1 ) dic_py[word_py] = mean_py f_py.close() |
筆順字典的處理方法也完全相同,雖然文本有兩萬行,導(dǎo)入還是很快的,0.5秒左右。如果把這兩個(gè)文件合并起來統(tǒng)一處理,應(yīng)該可以更快。
1
2
3
4
5
6
7
8
9
10
11
|
# 辭典查找函數(shù) def searchdict(dic,uchar): if isinstance (uchar, str ): uchar = unicode (uchar, 'utf-8' ) if uchar > = u '\u4e00' and uchar < = u '\u9fa5' : value = dic.get(uchar.encode( 'utf-8' )) if value = = None : value = '*' else : value = uchar return value |
查找中文,一律轉(zhuǎn)為UTF8字符串,漢字外的其他字符不做處理,原樣輸出。如果需要聲母,只輸出拼音的第一個(gè)字符就是了。只要資料準(zhǔn)確,比較起來就很輕松了。數(shù)字在字母之前,愛(ai4)便會比昂(ang2)靠前,而筆順值的位數(shù)代表了筆畫數(shù),數(shù)值對應(yīng)筆劃權(quán)重,直接比較數(shù)字大小就可以得到正確的順序。代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
#比較單個(gè)字符 def comp_char_PY(A,B): if A = = B: return - 1 pyA = searchdict(dic_py,A) pyB = searchdict(dic_py,B) if pyA > pyB: return 1 elif pyA < pyB: return 0 else : bhA = eval (searchdict(dic_bh,A)) bhB = eval (searchdict(dic_bh,B)) if bhA > bhB: return 1 elif bhA < bhB: return 0 else : return 'Are you kidding?' #比較字符串 def comp_char(A,B): charA = A.decode( 'utf-8' ) charB = B.decode( 'utf-8' ) n = min ( len (charA), len (charB)) i = 0 while i < n: dd = comp_char_PY(charA[i],charB[i]) if dd = = - 1 : i = i + 1 if i = = n: dd = len (charA)> len (charB) else : break return dd # 排序函數(shù) def cnsort(nline): n = len (nline) lines = '\n' .join(nline) for i in range ( 1 , n): #插入法 tmp = nline[i] j = i while j > 0 and comp_char(nline[j - 1 ],tmp): nline[j] = nline[j - 1 ] j - = 1 nline[j] = tmp return nline |
現(xiàn)在我們就可以按照字典的規(guī)范給中文排序了。
1
2
3
4
|
char = [ '趙' , '錢' , '孫' , '李' , '佘' ] char = cnsort(char) for item in char: print item.decode( 'utf-8' ).encode( 'gb2312' ) |
終于得到了“李錢佘孫趙”,示例文件點(diǎn)此下載。
這里我沒有考慮多音字的情況。如果想讓程序自動識別,可以增加多音詞組對照表,通過上下文來判斷。我不知道哪里有這樣的數(shù)據(jù),反正對于多音字不太多的情形,手動調(diào)整也就夠了。
希望本文所述對大家Python程序設(shè)計(jì)有所幫助。