在Python中使用NLTK查找押韵
我有一首诗,想用Python代码来打印出那些押韵的词。
到目前为止,我已经完成了:
- 用
wordpunct_tokenize()
把诗句分开。 - 清理这些词,去掉标点符号。
- 把每句诗的最后一个词存到一个列表里。
- 用
cmudict.entries()
生成另一个列表,里面包含这些最后一个词及其发音。
我现在卡在了下一步。应该怎么匹配这些发音呢?总的来说,我的主要任务是判断两个给定的词是否押韵。如果押韵,就返回True
,否则返回False
。
4 个回答
虽然来得有点晚,但我在做一个项目,目的是找到很多押韵的句子来处理。我开始是在这个问题讨论串里,受到kender的认可回答的启发。值得知道的是,当你要找成千上万的押韵时,可以利用字典查找来大大提高速度。
这个内容也更新到了python 3.x。
把CMU发音字典存成一个json文件,并写一个初始化函数和一个把条目从元组转换成字典的函数。
# global
json_entries = None
def tup2dict(tup, di):
for a, b in tup:
di.setdefault(a, []).append(b)
return di
def init_cmu(args):
import nltk
nltk.download('cmudict')
nltk.corpus.cmudict.ensure_loaded()
cmu_entries = nltk.corpus.cmudict.entries()
cmu_dict = dict()
tup2dict(cmu_entries, cmu_dict)
with open('./maps/cmu.json', 'w') as convert_file:
convert_file.write(json.dumps(cmu_dict))
如果你的脚本中有一个需要判断押韵的函数,可以在脚本的开头调用这个函数,以确保你可以访问到字典。
def require_rhyme_dict():
global json_entries
if json_entries:
return
try:
jsonf = open('./maps/cmu.json', 'r')
except:
pass
else:
# Global
json_entries = dict(json.load(jsonf))
jsonf.close()
print('json_entries loaded.')
最后,这里有一个修改过的kender的押韵函数,使用了字典和一种不同的子词检查方法(我遇到过一个边缘情况,押韵的词不是“lame”,但根据单词的起始索引和长度,这些词是不允许押韵的。具体例子我记不太清了,反正很少见)。
当连续调用几千次时,下面这个函数的调用速度比遍历所有nltk cmu条目来找到发音音节的列表要快得多。一如既往,level指的是两个词之间的发音音节数量,只有当这些音节在结尾处匹配时,才能算作押韵。在这个例子中,如果一个词有多种发音,也会对每个词进行检查。
def isContainSameWord(word1, word2):
if word1 in word2 or word2 in word1:
return True
else:
return False
def isRhyme(word1, word2, level):
require_rhyme_dict()
global json_entries
if isContainSameWord(word1, word2):
return False
word1_syllable_arrs = json_entries.get(word1)
word2_syllables_arrs = json_entries.get(word2)
if not word1_syllable_arrs or not word2_syllables_arrs:
return False
for a in word1_syllable_arrs:
for b in word2_syllables_arrs:
if a[-level:] == b[-level:]:
return True
return False
可以使用soundex或double metaphone这两种方法来判断单词是否押韵。NLTK这个库好像没有直接实现这些功能,不过你可以在网上快速搜索一下,会找到一些相关的实现。
Pronouncing
库在这方面表现得非常好。它不需要复杂的操作,加载速度快,而且是基于CMU发音词典,所以很可靠。
https://pypi.python.org/pypi/pronouncing
来自他们的文档:
>>> import pronouncing
>>> pronouncing.rhymes("climbing")
['diming', 'liming', 'priming', 'rhyming', 'timing']
在这里,我找到了一种使用NLTK来查找与给定单词押韵的方法:
def rhyme(inp, level):
entries = nltk.corpus.cmudict.entries()
syllables = [(word, syl) for word, syl in entries if word == inp]
rhymes = []
for (word, syllable) in syllables:
rhymes += [word for word, pron in entries if pron[-level:] == syllable[-level:]]
return set(rhymes)
其中,inp
是一个单词,而level
表示押韵的好坏程度。
所以你可以使用这个函数来检查两个单词是否押韵,只需查看其中一个单词是否在另一个单词的允许押韵列表中:
def doTheyRhyme(word1, word2):
# first, we don't want to report 'glue' and 'unglue' as rhyming words
# those kind of rhymes are LAME
if word1.find(word2) == len(word1) - len(word2):
return False
if word2.find(word1) == len(word2) - len(word1):
return False
return word1 in rhyme(word2, 1)