1. 程式人生 > >中文分句的一些想法(一)

中文分句的一些想法(一)

介紹

  筆者最近在做一個專案,需要用到中文分句,在此過程中有一些自己的想法,想要記錄下來,供讀者或自己以後參考。   所謂中文分句,就是將中文文章或段落中的句子拆分開來。一般,中文句子以。!?結尾,因此,一種自然的想法就是按照這些符號進行切分,但是這樣做效率比較低。另一種想法就是藉助NLTK,它支援多語言應用,如果能支援中文分句,那當然最好(筆者還未嘗試過,有機會可以試下),只是這方面的資料並不多。   本文將展示一個筆者自己在中文分句中的想法,主要以詩歌為測試物件,因此,並不是對所有的句子都能成功,這只是一個尚未成熟的想法。   在講這個想法前,我們需要了解一下這個想法用到的兩個Python模組——xpinyin和nltk 模組。

xpinyin

  xpinyin是Python中一個將中文轉化為其拼音的模組,藉助它,我們獲取漢字的拼音,其官方說明文件為:https://pypi.org/project/xpinyin/ 。   我們來看一下它的使用方法:

from xpinyin import Pinyin

sent = '功蓋三分國,名成八陣圖。'
test = Pinyin().get_pinyin(sent)
print(sent)
print(test)

其執行結果為:

功蓋三分國,名成八陣圖。
gong-gai-san-fen-guo-,-ming-cheng-ba-zhen-tu-。

該方法預設返回的分割符號為‘-’,如果想使用其它分隔符,可呼叫引數splitter。如果想顯示拼音的音調,可呼叫引數tone_marks 。示例如下:

from xpinyin import Pinyin

sent = '功蓋三分國,名成八陣圖。'
test = Pinyin().get_pinyin(sent, splitter=' ', tone_marks='marks')
print(sent)
print(test)

此時輸出結果為:

功蓋三分國,名成八陣圖。
gōng gài sān fēn guó , míng chéng bā zhèn tú 。

NLTK

  NLTK是python環境下NLP工具包,包含了豐富的文字處理和文字挖掘API。在這裡,我們只討論它的英語分句功能。   NLTK提供的句子劃分函式有sent_tokenize,PunktSentenceTokenizer等,我們以sent_tokenize為例:

import nltk
from pprint import pprint

# 產生文件
sample_text = '''We will discuss briefly about the basic syntax, structure and design philosophies.\
                 There is a defined hierarchical syntax for Python code which you should remember when writing code!\
                 Python is a really powerful programming language.
              '''
# 進行句子劃分
default_st = nltk.sent_tokenize
sample_sentences = default_st(text=sample_text)

# 輸出句子劃分後的資訊
print('Total sentences in sample_text:', len(sample_sentences))
print('Sample text sentences: ==>')
pprint(sample_sentences)

輸出結果如下:

Total sentences in sample_text: 3
Sample text sentences: ==>
['We will discuss briefly about the basic syntax, structure and design '
 'philosophies.',
 'There is a defined hierarchical syntax for Python code which you should '
 'remember when writing code!',
 'Python is a really powerful programming language.']

可以看到,sent_tokenize成功地將sample_text這個段落分為三句話。

詩歌分句

  接下來,將展示如何利用xpinyin和nltk來對古代詩歌進行分句。以下面的詩歌(杜甫《八陣圖》)為例:

功蓋三分國,名成八陣圖。江流石不轉,遺恨失吞吳。

利用xpinyin獲取其拼音(不帶聲調)為

gong gai san fen guo , ming cheng ba zhen tu 。 jiang liu shi bu zhuan , yi hen shi tun wu 。

替換其中的標點,將這句話轉化為英語,利用nltk進行分句,結果如下:

['gong gai san fen guo , ming cheng ba zhen tu .', 'jiang liu shi bu zhuan , yi hen shi tun wu .']

一共分為兩句。因此,中文文章也分為兩部分。但是如何判斷每一句的長度呢?我們以每一句(英語)中的空格數量加1為該句(中文)的長度,進行切分,得到的結果如下:

功蓋三分國,名成八陣圖。
江流石不轉,遺恨失吞吳。

  大致想法就是這樣,我們將這個想法轉化為程式碼,完整的Python程式碼如下:

import nltk
from xpinyin import Pinyin

# 詩歌分句
def split_sentence(sent):
    sent = sent.replace('\n', '').replace('《', '').replace("》", '')
    test = Pinyin().get_pinyin(sent, splitter=' ')
    # 標點替換
    biaodian_dict = {'。': '.', ',': ',', '!': '!', '?': '?'}
    for key, value in biaodian_dict.items():
        test = test.replace(key, value)
    # 英文分句
    sample_sentences = nltk.sent_tokenize(text=test)
    # 統計每個句子的長度
    part_length = []
    for string in sample_sentences:
        part_length.append(string.count(' ') + 1)
    # 中文分句
    split_2_parts(part_length, sent)

# 按句子的長度進行分句
def split_2_parts(part_length, sentences):
    sent_list = []; start = 0
    for i in range(len(part_length)):
        sent_list.append(sentences[start:start+part_length[i]])
        start += part_length[i]

    print('共分為%d句。'%len(sent_list))
    for _ in sent_list:
        print(_)

sent = '功蓋三分國,名成八陣圖。江流石不轉,遺恨失吞吳。'
split_sentence(sent)

輸出結果如下:

共分為2句。
功蓋三分國,名成八陣圖。
江流石不轉,遺恨失吞吳。

下面,我們對其它詩句進行測試,前一部分為詩歌,後一部分為詩歌切分後的輸出。

sent = '繁華事散逐香塵,流水無情草自春。日暮東風怨啼鳥,落花猶似墜樓人。'
split_sentence(sent)
共分為2句。
繁華事散逐香塵,流水無情草自春。
日暮東風怨啼鳥,落花猶似墜樓人。
sent = '今夜鄜州月,閨中只獨看。遙憐小兒女,未解憶長安。香霧雲鬟溼,清輝玉臂寒。何時倚虛幌,雙照淚痕幹。'
split_sentence(sent)
共分為4句。
今夜鄜州月,閨中只獨看。
遙憐小兒女,未解憶長安。
香霧雲鬟溼,清輝玉臂寒。
何時倚虛幌,雙照淚痕幹。
sent = '客路青山外,行舟綠水前。潮平兩岸闊,風正一帆懸。海日生殘夜,江春入舊年。鄉書何處達?歸雁洛陽邊。'
split_sentence(sent)
共分為5句。
客路青山外,行舟綠水前。
潮平兩岸闊,風正一帆懸。
海日生殘夜,江春入舊年。
鄉書何處達?
歸雁洛陽邊。
sent = '花近高樓傷客心,萬方多難此登臨。錦江春色來天地,玉壘浮雲變古今。北極朝廷終不改,西山寇盜莫相侵。可憐後主還祠廟,日暮聊為《樑甫吟》。'
split_sentence(sent)
共分為4句。
花近高樓傷客心,萬方多難此登臨。
錦江春色來天地,玉壘浮雲變古今。
北極朝廷終不改,西山寇盜莫相侵。
可憐後主還祠廟,日暮聊為樑甫吟。
sent = '山石犖确行徑微,黃昏到寺蝙蝠飛。升堂坐階新雨足,芭蕉葉大梔子肥。' \
       '僧言古壁佛畫好,以火來照所見稀。鋪床拂席置羹飯,疏糲亦足飽我飢。' \
       '夜深靜臥百蟲絕,清月出嶺光入扉。天明獨去無道路,出入高下窮煙霏。' \
       '山紅澗碧紛爛漫,時見鬆櫪皆十圍。當流赤足踏澗石,水聲激激風吹衣。' \
       '人生如此自可樂,豈必局束為人鞿?嗟哉吾黨二三子,安得至老不更歸。'
split_sentence(sent)
共分為10句。
山石犖确行徑微,黃昏到寺蝙蝠飛。
升堂坐階新雨足,芭蕉葉大梔子肥。
僧言古壁佛畫好,以火來照所見稀。
鋪床拂席置羹飯,疏糲亦足飽我飢。
夜深靜臥百蟲絕,清月出嶺光入扉。
天明獨去無道路,出入高下窮煙霏。
山紅澗碧紛爛漫,時見鬆櫪皆十圍。
當流赤足踏澗石,水聲激激風吹衣。
人生如此自可樂,豈必局束為人鞿?
嗟哉吾黨二三子,安得至老不更歸。

最後是著名的《長恨歌》:

sent = '''
漢皇重色思傾國,御宇多年求不得。楊家有女初長成,養在深閨人未識。天生麗質難自棄,一朝選在君王側。回眸一笑百媚生,六宮粉黛無顏色。
春寒賜浴華清池,溫泉水滑洗凝脂。侍兒扶起嬌無力,始是新承恩澤時。雲鬢花顏金步搖,芙蓉帳暖度春宵。春宵苦短日高起,從此君王不早朝。
承歡侍宴無閒暇,春從春遊夜專夜。後宮佳麗三千人,三千寵愛在一身。金屋妝成嬌侍夜,玉樓宴罷醉和春。姊妹弟兄皆列土,可憐光彩生門戶。
遂令天下父母心,不重生男重生女。驪宮高處入青雲,仙樂風飄處處聞。緩歌慢舞凝絲竹,盡日君王看不足。漁陽鼙鼓動地來,驚破霓裳羽衣曲。
九重城闕煙塵生,千乘萬騎西南行。翠華搖搖行復止,西出都門百餘里。六軍不發無奈何,宛轉蛾眉馬前死。花鈿委地無人收,翠翹金雀玉搔頭。
君王掩面救不得,回看血淚相和流。黃埃散漫風蕭索,雲棧縈紆登劍閣。峨嵋山下少人行,旌旗無光日色薄。蜀江水碧蜀山青,聖主朝朝暮暮情。
行宮見月傷心色,夜雨聞鈴腸斷聲。天旋地轉回龍馭,到此躊躇不能去。馬嵬坡下泥土中,不見玉顏空死處。君臣相顧盡沾衣,東望都門信馬歸。
歸來池苑皆依舊,太液芙蓉未央柳。芙蓉如面柳如眉,對此如何不淚垂。春風桃李花開日,秋雨梧桐葉落時。西宮南內多秋草,落葉滿階紅不掃。
梨園弟子白髮新,椒房阿監青娥老。夕殿螢飛思悄然,孤燈挑盡未成眠。遲遲鐘鼓初長夜,耿耿星河欲曙天。鴛鴦瓦冷霜華重,翡翠衾寒誰與共。
悠悠生死別經年,魂魄不曾來入夢。臨邛道士鴻都客,能以精誠致魂魄。為感君王輾轉思,遂教方士殷勤覓。排空馭氣奔如電,昇天入地求之遍。
上窮碧落下黃泉,兩處茫茫皆不見。忽聞海上有仙山,山在虛無縹渺間。樓閣玲瓏五雲起,其中綽約多仙子。中有一人字太真,雪膚花貌參差是。
金闕西廂叩玉扃,轉教小玉報雙成。聞道漢家天子使,九華帳裡夢魂驚。攬衣推枕起徘徊,珠箔銀屏迤邐開。雲鬢半偏新睡覺,花冠不整下堂來。
風吹仙袂飄飄舉,猶似霓裳羽衣舞。玉容寂寞淚闌干,梨花一枝春帶雨。含情凝睇謝君王,一別音容兩渺茫。昭陽殿裡恩愛絕,蓬萊宮中日月長。
回頭下望人寰處,不見長安見塵霧。惟將舊物表深情,鈿合金釵寄將去。釵留一股合一扇,釵擘黃金合分鈿。但教心似金鈿堅,天上人間會相見。
'''
split_sentence(sent)

劃分後的結果如下:

共分為56句。
漢皇重色思傾國,御宇多年求不得。
楊家有女初長成,養在深閨人未識。
天生麗質難自棄,一朝選在君王側。
回眸一笑百媚生,六宮粉黛無顏色。
春寒賜浴華清池,溫泉水滑洗凝脂。
侍兒扶起嬌無力,始是新承恩澤時。
雲鬢花顏金步搖,芙蓉帳暖度春宵。
春宵苦短日高起,從此君王不早朝。
承歡侍宴無閒暇,春從春遊夜專夜。
後宮佳麗三千人,三千寵愛在一身。
金屋妝成嬌侍夜,玉樓宴罷醉和春。
姊妹弟兄皆列土,可憐光彩生門戶。
遂令天下父母心,不重生男重生女。
驪宮高處入青雲,仙樂風飄處處聞。
緩歌慢舞凝絲竹,盡日君王看不足。
漁陽鼙鼓動地來,驚破霓裳羽衣曲。
九重城闕煙塵生,千乘萬騎西南行。
翠華搖搖行復止,西出都門百餘里。
六軍不發無奈何,宛轉蛾眉馬前死。
花鈿委地無人收,翠翹金雀玉搔頭。
君王掩面救不得,回看血淚相和流。
黃埃散漫風蕭索,雲棧縈紆登劍閣。
峨嵋山下少人行,旌旗無光日色薄。
蜀江水碧蜀山青,聖主朝朝暮暮情。
行宮見月傷心色,夜雨聞鈴腸斷聲。
天旋地轉回龍馭,到此躊躇不能去。
馬嵬坡下泥土中,不見玉顏空死處。
君臣相顧盡沾衣,東望都門信馬歸。
歸來池苑皆依舊,太液芙蓉未央柳。
芙蓉如面柳如眉,對此如何不淚垂。
春風桃李花開日,秋雨梧桐葉落時。
西宮南內多秋草,落葉滿階紅不掃。
梨園弟子白髮新,椒房阿監青娥老。
夕殿螢飛思悄然,孤燈挑盡未成眠。
遲遲鐘鼓初長夜,耿耿星河欲曙天。
鴛鴦瓦冷霜華重,翡翠衾寒誰與共。
悠悠生死別經年,魂魄不曾來入夢。
臨邛道士鴻都客,能以精誠致魂魄。
為感君王輾轉思,遂教方士殷勤覓。
排空馭氣奔如電,昇天入地求之遍。
上窮碧落下黃泉,兩處茫茫皆不見。
忽聞海上有仙山,山在虛無縹渺間。
樓閣玲瓏五雲起,其中綽約多仙子。
中有一人字太真,雪膚花貌參差是。
金闕西廂叩玉扃,轉教小玉報雙成。
聞道漢家天子使,九華帳裡夢魂驚。
攬衣推枕起徘徊,珠箔銀屏迤邐開。
雲鬢半偏新睡覺,花冠不整下堂來。
風吹仙袂飄飄舉,猶似霓裳羽衣舞。
玉容寂寞淚闌干,梨花一枝春帶雨。
含情凝睇謝君王,一別音容兩渺茫。
昭陽殿裡恩愛絕,蓬萊宮中日月長。
回頭下望人寰處,不見長安見塵霧。
惟將舊物表深情,鈿合金釵寄將去。
釵留一股合一扇,釵擘黃金合分鈿。
但教心似金鈿堅,天上人間會相見。

中文分句

  接下來,我們對其它的中文段落進行分句,來看看這個想法的效果。需要注意的是,段落中不能出現:“”%等符號,這是因為之前的程式碼中並沒有處理這類符號,如果想要能處理這類符號,讀者可以自己修改剛才的程式碼。

新聞:

sent = '''
隨著美國中期選舉的迫近,特朗普為維持自己的經濟成果,多次按自己的意圖向美國相關部門施壓,
其中包括要求美國財政部把中國列為匯率操縱國。但今天早上的報告顯示,美國財政部並未跟隨特朗普的政策。
除此之外,稍早前的美聯儲在特朗普的炮火中,堅持對美元加息,以保持自己的獨立性。
'''
split_sentence(sent)

輸出結果為:

隨著美國中期選舉的迫近,特朗普為維持自己的經濟成果,多次按自己的意圖向美國相關部門施壓,其中包括要求美國財政部把中國列為匯率操縱國。
但今天早上的報告顯示,美國財政部並未跟隨特朗普的政策。
除此之外,稍早前的美聯儲在特朗普的炮火中,堅持對美元加息,以保持自己的獨立性。

散文《背影》片段:

sent = '''
我們過了江,進了車站。
我買票,他忙著照看行李。
行李太多了,得向腳伕行些小費,才可過去。
他便又忙著和他們講價錢。
我那時真是聰明過分,總覺他說話不大漂亮,非自己插嘴不可。
但他終於講定了價錢;就送我上車。
他給我揀定了靠車門的一張椅子;我將他給我做的紫毛大衣鋪好坐位。
他囑我路上小心,夜裡警醒些,不要受涼。又囑託茶房好好照應我。
我心裡暗笑他的迂;他們只認得錢,託他們直是白託!
而且我這樣大年紀的人,難道還不能料理自己麼?
唉,我現在想想,那時真是太聰明瞭! 
'''
split_sentence(sent)

輸出結果為:

共分為12句。
我們過了江,進了車站。
我買票,他忙著照看行李。
行李太多了,得向腳伕行些小費,才可過去。
他便又忙著和他們講價錢。
我那時真是聰明過分,總覺他說話不大漂亮,非自己插嘴不可。
但他終於講定了價錢;就送我上車。
他給我揀定了靠車門的一張椅子;我將他給我做的紫毛大衣鋪好坐位。
他囑我路上小心,夜裡警醒些,不要受涼。
又囑託茶房好好照應我。
我心裡暗笑他的迂;他們只認得錢,託他們直是白託!
而且我這樣大年紀的人,難道還不能料理自己麼?
唉,我現在想想,那時真是太聰明瞭!

&ems; 當然這個想法並不是完美的,碰到標點符號連在一起的情況等,就容易出錯。而且,只要中間有一個錯了,後面的就會全錯。因此,該想法還有待改進,但對於詩歌分詞,效果還是不錯的,後續的文章中還會繼續用到這個想法。

  如果讀者知道其他更好的辦法,請隨時聯絡筆者或留言。本文到此結束,歡迎大家交流~

注意:本人現已開通微信公眾號: Python爬蟲與演算法(微訊號為:easy_web_scrape), 歡迎大家關注哦~~