HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

A Very Poetic Program

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
programpoeticvery

Problem

This program is basically a rhyming dictionary. It makes use of Sphinx's groups phonemic dictionary of English which includes a lot of words broken into their respective phonemes, and if we assume that, at least for most cases, anytime the two last phonemes match, the two words rhyme, then it's very easy to whip up a program that does so. Here's my try at this:

import requests
import os
import re

def load_library():
    with open('library.txt', 'r') as library:
        lines = library.readlines()

    return [x for x in lines if not x.startswith(';;;')]

def rhyme(string):

    if os.path.isfile('library.txt'):
        library = load_library()
    else:
        url = "http://svn.code.sf.net/p/cmusphinx/code/trunk/cmudict/cmudict-0.7b"
        response = requests.get(url, stream=True)

        if not response.ok:
            print("Error loading library")

        with open('library.txt', 'wb+') as library:
            for block in response.iter_content(32):
                library.write(block)

    library = load_library()
    string = string.upper()

    phonemes = [y for y in library if y.startswith(string)][0][len(string):]
    phonemes_split = str.strip(phonemes).split(' ')

    matches = [z for z in library if z.endswith(phonemes_split[-2] + ' ' + phonemes_split[-1] + '\n')]
    matches = [z.strip().split(' ') for z in matches]

    return matches


Of course it's naive to assume that EVERYTIME the last two phonemes of two different words match, they rhyme, but most of the times, they do.

This program returns a list of matching words broken into their respective phonemes.

I spent two years studying English literature before I dropped out in favor of pursuing computer programming so I'm qualified to say that I barely know what a phoneme is.

Solution

Library loaded twice

If library.txt exists, it will get loaded twice:

if os.path.isfile('library.txt'):
    library = load_library()
else:
    # download the file ...

library = load_library()


I guess this was just an oversight, with a simple fix:

if not os.path.isfile('library.txt'):
    # download the file ...

library = load_library()


Filter while loading

Instead of loading the library first and then filtering out the commented lines, it would be better to filter as you read:

with open('library.txt', 'r') as library:
    return [line for line in library if not line.startswith(';;;')]


Use generator expressions for better performance

It's a pity to loop over the entire list and filtering when you will only use the first match:

phonemes = [y for y in library if y.startswith(string)][0][len(string):]


You would do better with a generator expression,
which is more or less as simple as replacing the surrounding [...] with (...).
However, generators are not subscriptable, so to get the first element you must use the next(...) builtin:

phonemes = next(y for y in library if y.startswith(string))[len(string):]

Code Snippets

if os.path.isfile('library.txt'):
    library = load_library()
else:
    # download the file ...

library = load_library()
if not os.path.isfile('library.txt'):
    # download the file ...

library = load_library()
with open('library.txt', 'r') as library:
    return [line for line in library if not line.startswith(';;;')]
phonemes = [y for y in library if y.startswith(string)][0][len(string):]
phonemes = next(y for y in library if y.startswith(string))[len(string):]

Context

StackExchange Code Review Q#140029, answer score: 5

Revisions (0)

No revisions yet.