-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathmultisyllabic_rhymer.py
141 lines (101 loc) · 4.05 KB
/
multisyllabic_rhymer.py
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import pronouncing
import string
import copy
import sys
CONSONANTS = set(string.ascii_uppercase)-set('AEIOU')
def get_phones(word):
"""
Given a user-inputted word, return phones, its corresponding list of phonemes.
For example, the input guitar yields the list ['G', 'IH0', 'T', 'AA1', 'R']
"""
phones_for_word = pronouncing.phones_for_word(word)
if not phones_for_word:
return None
phones = phones_for_word[0].split()
return phones
def _get_vowel_index(phones):
"""
In preparation to search for slant rhymes, return the position of the first vowel in phones.
"""
for index, phone in enumerate(phones):
if phone[0] in 'AEIOU':
return index
def _get_consonant_indices(phones):
"""
In preparation to search for slant rhymes, return the positions of all intermediate consonants after the first vowel in phones.
"""
indices = []
for index, phone in enumerate(phones):
if phone[0] in CONSONANTS and index < len(phones) - 1:
indices.append(index)
return indices
def _get_rhyming_tail(phones):
"""
In preparation to search for multisyllabic rhymes, remove characters before the first vowel in phones.
For example, phones changes from ['G', 'IH0', 'T', 'AA1', 'R'] to ['IH0', 'T', 'AA1', 'R']
"""
index = _get_vowel_index(phones)
return phones[index:]
def _slant_rhyme_consonants(phones):
"""
Replaces intermediate consonants with a period, the wildcard character. The final consonant is preserved.
For example, replace the intermediate 'T' in ['IH0', 'T', 'AA1', 'R'], leaving ['IH0', '.', 'AA1', 'R']
"""
consonant_indices = _get_consonant_indices(phones)
new_phones = copy.copy(phones)
for index in consonant_indices:
new_phones[index] = '.'
return new_phones
def get_perfect_rhymes(phones):
"""
Given phones, search for perfect, multisyllabic rhymes with no syllables afterwards.
"""
rhyming_tail = " ".join(_get_rhyming_tail(phones))
return pronouncing.search(rhyming_tail + "$")
def get_internal_rhymes(phones):
"""
Given phones, search for internal, multisyllabic rhymes.
"""
rhyming_tail = " ".join(_get_rhyming_tail(phones))
return pronouncing.search(rhyming_tail)
def get_slant_rhymes(phones):
"""
Given phones, return all slant and internal rhymes.
Slant rhymes do not require matching consonants before the final position. For example, guitar and cigar.
Internal rhymes do not require the matching syllables to be final. For example, guitar and departure.
"""
tail = _get_rhyming_tail(phones)
search = ' '.join(_slant_rhyme_consonants(tail))
return pronouncing.search(search)
def main(word):
"""
Search for slant rhymes given word, an argument from the command line.
For an inputted word not recognized in the CMU dictionary, prompt user to try another word.
"""
phones = get_phones(word)
if phones is None:
print('That word is not recognized. Please check the spelling and avoid proper nouns.')
exit(1)
perfect_rhymes = get_perfect_rhymes(phones)
internal_rhymes = get_internal_rhymes(phones)
slant_rhymes = get_slant_rhymes(phones)
perfects_without_word = set(perfect_rhymes) - {word}
internals_without_perfects = set(internal_rhymes) - set(perfect_rhymes) - {word}
imperfect_slants = set(slant_rhymes) - set(internal_rhymes) - {word}
if perfects_without_word:
print('Perfect rhymes:', ", ".join(sorted(perfects_without_word)), '\n')
else:
print('No perfect rhymes.\n')
if internals_without_perfects:
print('Internal rhymes:', ", ".join(sorted(internals_without_perfects)), '\n')
else:
print('No internal rhymes.\n')
if imperfect_slants:
print('Slant rhymes:', ", ".join(sorted(imperfect_slants)))
else:
print('No slant rhymes.')
if __name__ == '__main__':
if len(sys.argv) < 2:
print('Usage: multisyllabic_rhymer.py word, where word is the rhyme target.')
exit(1)
main(sys.argv[1])