jclian91

介绍

  笔者最近在做一个项目,需要用到中文分句,在此过程中有一些自己的想法,想要记录下来,供读者或自己以后参考。
  所谓中文分句,就是将中文文章或段落中的句子拆分开来。一般,中文句子以。!?结尾,因此,一种自然的想法就是按照这些符号进行切分,但是这样做效率比较低。另一种想法就是借助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), 欢迎大家关注哦~~

相关文章:

  • 2021-10-29
  • 2021-04-16
  • 2021-07-25
  • 2021-08-09
  • 2021-09-08
  • 2021-11-05
  • 2021-12-05
猜你喜欢
  • 2021-02-15
  • 2022-01-10
  • 2021-11-10
  • 2021-11-05
  • 2021-09-05
  • 2021-07-31
  • 2021-09-08
相关资源
相似解决方案