File size: 4,144 Bytes
e0171fd |
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]) |