loading...

Daily Challenge #229 - Haiku Validator

thepracticaldev profile image dev.to staff ・2 min read

Haikus are short poems in a three-line format, with 17 syllables arranged in a 5–7–5 pattern. Implement a function to check if the supplied text is a haiku or not.

Syllables are the phonological building blocks of words. In this challenge, a syllable is a part of a word including a vowel ("a-e-i-o-u-y") or a group of vowels (e.g. "ou", "ee", "ay"). A few examples: "tea", "can", "to·day", "week·end", "el·e·phant".

However, silent "E"s do not create syllables. An "E" is considered silent if it's alone at the end of the word, preceded by one (or more) consonant(s) and there is at least one other syllable in the word. Examples: "age", "ar·range", "con·crete"; but not in "she", "blue", "de·gree".

Some more examples:

one syllable words: "cat", "cool", "sprout", "like", "eye", "squeeze"
two syllables words: "ac·count", "hon·est", "beau·ty", "a·live", "be·cause", "re·store"

Examples

An old silent pond...
A frog jumps into the pond,
splash! Silence again.

...should return True, as this is a valid 5–7–5 haiku


An old si·lent pond...            # 5 syllables
A frog jumps in·to the pond,      # 7
splash! Si·lence a·gain.          # 5

This one is good too!


Au·tumn moon·light -          # 4 syllables
a worm digs si·lent·ly        # 6
in·to the chest·nut.          # 5

...should return False, because the number of syllables per line is incorrect.

Tests

1.
My code is cool, right?
Java # Python ; Ruby // Go:
I know them all, yay!

2.
An old silent pond...
A frog jumps into the pond, splash!
Silence again

Good Luck!


This challenge comes from anter69 on CodeWars. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!

Posted on by:

thepracticaldev profile

dev.to staff

@thepracticaldev

The hardworking team behind dev.to ❤️

Discussion

markdown guide
 

I enjoyed this one; I'm always a fan of mixing poetry and code. My Python solution is below.

I decided that the haiku came as single strings, with lines separated by \n, so the solution only works with haiku in that format. The only module required is re, for vowel counting.

Code

The solution rests on three small functions. The first is the clean_haiku function, which takes a single haiku string and processes it, returning a list of lower-case lines with all punctuation removed.

def clean_haiku(haiku):
    lines = haiku.split("\n")
    lines = [line.lower()
                 .replace("[^a-z]","")
                 .strip() for line in lines]
    return lines

The next function takes a single line as a string and returns a list of syllables. It does this by splitting the line into words, and then, for each word, counting clusters (1+) of vowels. The number of clusters in a word is (once you account for edge cases) the number of syllables.

def count_syllables(line):
  words = line.split(" ")
  count = 0
  for word in words:
    matches = re.findall("[aeiouy]+", word)
    if word.endswith("e") and len(matches) > 1:
        count -= 1
    count += len(matches)
  return count

The final function - validate_haiku takes a haiku string and calls clean_haiku to get processed lines, and then count_syllables for each line. If the final list of syllable counts matches [5, 7, 5], then the function returns True.

def validate_haiku(haiku):
    lines = clean_haiku(haiku)
    if len(lines) != 3:
        return False
    counts = [count_syllables(line) for line in lines]
    if counts != [5, 7, 5]:
        return False
    return True

Tests

tests = ["An old silent pond...\nA frog jumps into the pond,\nsplash! Silence again.",
         "My code is cool, right?\nJava # Python ; Ruby // Go:\nI know them all, yay!",
         "Autumn moonlight -\naworm digs silently\ninto the chestnut."]

for test in tests:
    print(validate_haiku(test))

# True
# True
# False
 

Lemme check if this works though:

"Haikus are easy\n
But sometimes they don’t make sense\n
Refrigerator"

test shows false for it :p

 

You're absolutely right - my code passes the tests outlined above, but there are various edge cases that trip it up. "Sometimes" is one of them, because it's only two syllables really but contains two silent "e"s which register as syllables with this simplistic definition. Another one is "abalone", because the "e" at the end is pronounced as a separate syllable.

You can get the function closer to correct by changing the count_syllables function like so

if (word.endswith("e") or word.endswith("es")) and len(matches) > 1:

but it still struggles with that "ome".

Counting syllables is actually a really complex problem if you want to hit all the edge cases - this article goes into it more deeply. In the end, the best way is to use some kind of dictionary lookup, but that will still fail with unknown words.