本文主要介紹如何通過(guò)預(yù)先設(shè)定好的語(yǔ)法規(guī)則以及單詞,通過(guò)Python來(lái)自動(dòng)生成一些句子。
解析語(yǔ)法
在生成句子之前,我們需要先告訴機(jī)器生成句子的語(yǔ)法。
因此,我們先定義一個(gè)簡(jiǎn)單的語(yǔ)法:
simple_grammar = """
sentence => noun_phrase verb_phrase
noun_phrase => Article Adj* noun
Adj* => null | Adj Adj*
verb_phrase => verb noun_phrase
Article => 一個(gè) | 這個(gè)
noun => 女人 | 籃球 | 桌子 | 小貓
verb => 看著 | 坐在 | 聽(tīng)著 | 看見(jiàn)
Adj => 藍(lán)色的 | 好看的 | 小小的
"""
上面的語(yǔ)法其實(shí)可以表示成一棵語(yǔ)法樹(shù)(Syntax Tree),對(duì)此感興趣的話可以參考以下文章:
語(yǔ)法說(shuō)明
-
sentence => noun_phrase verb_phrase:表示一個(gè)sentence由noun_phrase和verb_phrase組成。 -
Adj => 藍(lán)色的 | 好看的 | 小小的:表示Adj一共有藍(lán)色的 | 好看的 | 小小的3個(gè)選擇。
基于上面的兩條規(guī)說(shuō)明,我們就能夠讀懂上面的語(yǔ)法規(guī)則。
觀察上面的語(yǔ)法,我們可以發(fā)現(xiàn)一共有兩類(lèi)詞匯,左邊的詞匯是可以繼續(xù)拓展的,右邊的詞匯如果不在左邊,那么是不可拓展的。
我們先以adj為例,編寫(xiě)代碼。Adj語(yǔ)法如下:
adj_grammar = """
Adj* => null | Adj Adj*
Adj => 藍(lán)色的 | 好看的 | 小小的
"""
根據(jù)上面的adj_grammar字符串語(yǔ)法規(guī)則,我們將其解析成字典格式:
# 解析語(yǔ)法
def create_grammar(grammar_str, split = '=>', line_split = '\n'):
grammar = {}
for line in grammar_str.split(line_split):
if not line.strip():
continue # 跳過(guò)空行
else:
exp, stmt = line.split(split)
grammar[exp.strip()] = [s.split() for s in stmt.split('|')]
return grammar
結(jié)果如下:

接著我們?cè)賹⑸厦娴?code>simple_grammar語(yǔ)法規(guī)則解析成字典格式:

至此,我們已經(jīng)能夠使用代碼解析出上面的語(yǔ)法規(guī)則了。
生成句子
最后,我們編寫(xiě)代碼根據(jù)上面的語(yǔ)法規(guī)則,自動(dòng)生成句子:
# 生成句子
def generate(gram, target):
if target not in gram:
return target # means target is a terminal expression
# target in gram 意味著target是可以繼續(xù)拓展下去的
else:
expaned = [generate(gram, t) for t in random.choice(gram[target])]
return ''.join([e if e!='/n' else '\n' for e in expaned if e != 'null'])
利用編寫(xiě)的代碼,隨機(jī)生成一個(gè)句子:

我們可以再定義兩個(gè)語(yǔ)法,看一下效果如何:
# 在西部世界里
# 一個(gè)”人類(lèi)“的語(yǔ)言可以定義為:
human = """
human = 自己 尋找 活動(dòng)
自己 = 我 | 俺 | 我們
尋找 = 找找 | 想找點(diǎn)
活動(dòng) = 樂(lè)子 | 玩的
"""
# 一個(gè)“接待員”的語(yǔ)言可以定義為
host = """
host = 寒暄 報(bào)數(shù) 詢問(wèn) 業(yè)務(wù)相關(guān) 結(jié)尾
報(bào)數(shù) = 我是 數(shù)字 號(hào) ,
數(shù)字 = 單個(gè)數(shù)字 | 數(shù)字 單個(gè)數(shù)字
單個(gè)數(shù)字 = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
寒暄 = 稱(chēng)謂 打招呼 | 打招呼
稱(chēng)謂 = 人稱(chēng) ,
人稱(chēng) = 先生 | 女士 | 小朋友
打招呼 = 你好 | 您好
詢問(wèn) = 請(qǐng)問(wèn)你要 | 您需要
業(yè)務(wù)相關(guān) = 玩玩 具體業(yè)務(wù)
玩玩 = null
具體業(yè)務(wù) = 喝酒 | 打牌 | 打獵 | 賭博
結(jié)尾 = 嗎?
"""
“人類(lèi)”和“接待員”各自隨機(jī)生成5個(gè)句子:

可以看到,我們已經(jīng)成功地通過(guò)自定義的語(yǔ)法規(guī)則來(lái)讓計(jì)算機(jī)自動(dòng)生成句子了。
小結(jié)
本文主要通過(guò)解析語(yǔ)法樹(shù),自動(dòng)生成句子等方法,實(shí)現(xiàn)了一個(gè)自動(dòng)生成句子的程序。
看完這篇文章,大家也可以設(shè)計(jì)實(shí)現(xiàn)自己的句子生成器。
上面生成了許多句子,但是,我們?nèi)绾闻袛嗄男┚渥痈鼮楹侠恚ǚ先祟?lèi)說(shuō)話習(xí)慣),哪些句子不合理?這時(shí)候就需要用到語(yǔ)言模型了,關(guān)于語(yǔ)言模型的相關(guān)概念及代碼實(shí)現(xiàn),將會(huì)在后面的文章講到,敬請(qǐng)期待。