patternpythonMinor
Haikuifier (Or at least Haiku Identifier)
Viewed 0 times
identifierhaikuifierhaikuleast
Problem
All the usual stuff. Style, substance, algorithm please! I'm vaguely considering plugging it into a bot, hence the lacklustre catching of exceptions right now.
```
import requests
import sys
def get_num_syllables(value):
try:
res = requests.get("http://www.thefreedictionary.com/" + value)
except requests.exceptions.ConnectionError as e:
return -1
for word in res.text.split():
if "" not in word:
continue
word = word[word.find("")+ 4:word.find("")]
if '·' in word:
return word.count('·') + 1
if "Word not found in the Dictionary and Encyclopedia." in res.text:
return -1
return 1
def haikuify(sentence):
sentence = sentence.strip()
num_syllables = []
for word in sentence.split():
num_syllables.append(get_num_syllables(word))
if -1 in num_syllables:
raise SyntaxError("Someone can't spell - can't find a word from the sentence in the dictionary")
haiku_form = [5, 7, 5]
haiku_indices = []
i = -1
run = 0
line = 0
for value in num_syllables:
run += value
if run is haiku_form[line]:
haiku_indices.append(i)
line += 1
run = 0
elif run > haiku_form[line]:
raise SyntaxError("Not a haiku")
break
i += 1
haiku_indices.append(len([len(x) for x in sentence.split()]) - 1)
if len(haiku_indices) is not 3:
raise SyntaxError("Not a haiku")
i = -1
line = 0
this_line = ""
haiku = []
for word in sentence.split():
word = word.replace(" ", "")
if not word:
continue
this_line += " " + word
i += 1
if i is haiku_indices[line]:
haiku.append(this_line)
this_line = ""
line += 1
return haiku
if __name__ == "__main__":
sentence = input("Sentence to haikuify: ")
haiku = []
try:
haiku = haikuify(sentence)
ex
```
import requests
import sys
def get_num_syllables(value):
try:
res = requests.get("http://www.thefreedictionary.com/" + value)
except requests.exceptions.ConnectionError as e:
return -1
for word in res.text.split():
if "" not in word:
continue
word = word[word.find("")+ 4:word.find("")]
if '·' in word:
return word.count('·') + 1
if "Word not found in the Dictionary and Encyclopedia." in res.text:
return -1
return 1
def haikuify(sentence):
sentence = sentence.strip()
num_syllables = []
for word in sentence.split():
num_syllables.append(get_num_syllables(word))
if -1 in num_syllables:
raise SyntaxError("Someone can't spell - can't find a word from the sentence in the dictionary")
haiku_form = [5, 7, 5]
haiku_indices = []
i = -1
run = 0
line = 0
for value in num_syllables:
run += value
if run is haiku_form[line]:
haiku_indices.append(i)
line += 1
run = 0
elif run > haiku_form[line]:
raise SyntaxError("Not a haiku")
break
i += 1
haiku_indices.append(len([len(x) for x in sentence.split()]) - 1)
if len(haiku_indices) is not 3:
raise SyntaxError("Not a haiku")
i = -1
line = 0
this_line = ""
haiku = []
for word in sentence.split():
word = word.replace(" ", "")
if not word:
continue
this_line += " " + word
i += 1
if i is haiku_indices[line]:
haiku.append(this_line)
this_line = ""
line += 1
return haiku
if __name__ == "__main__":
sentence = input("Sentence to haikuify: ")
haiku = []
try:
haiku = haikuify(sentence)
ex
Solution
You should be more helpful to the user, both when the entered sentence can't be made into a haiku (too short or too long) and when not finding the word in the dictionary. At least tell which word was not found in the dictionary.
Also when
You dictionary lookup fails for some words:
I tested your program with this haiku from wikipedia:
Snow in my shoe
Abandoned
Sparrow's nest
— Jack Kerouac, collected in Book of Haikus, 2003
And this:
Whitecaps on the bay:
A broken signboard banging
In the April wind.
— Richard Wright, collected in Haiku: This Other World, 1998
The first raises a
What your code also does not catch is that thefreedictionary puts a flood mechanism into place after some time. I found this out by testing my own script. In this case the fifth request in a row returns with HTTP code 403 (Access forbidden).
How I would write it:
Also when
thefreedictionary.com is not reachable (for whatever reasons), your code will insult the user by telling him he can't spell.You dictionary lookup fails for some words:
- "sparrow's", or any possessive form (raises SyntaxError)
- "banging", or any gerund form. (gives the syllables of the infinitive instead)
- Any punctuation (also raises SyntaxError)
I tested your program with this haiku from wikipedia:
Snow in my shoe
Abandoned
Sparrow's nest
— Jack Kerouac, collected in Book of Haikus, 2003
And this:
Whitecaps on the bay:
A broken signboard banging
In the April wind.
— Richard Wright, collected in Haiku: This Other World, 1998
The first raises a
SyntaxError and the second puts In on the end of the second line because of the gerund counting as one less syllable.What your code also does not catch is that thefreedictionary puts a flood mechanism into place after some time. I found this out by testing my own script. In this case the fifth request in a row returns with HTTP code 403 (Access forbidden).
How I would write it:
import requests
import sys
import re
def get_num_syllables(value):
if value.endswith("ing"):
return get_num_syllables(value[:-3]) + 1
try:
res = requests.get("http://www.thefreedictionary.com/" + value)
except requests.exceptions.ConnectionError as e:
print("Can't connect to dictionary website: http://www.thefreedictionary.com/" + value)
sys.exit(1)
if res.status_code != 200:
raise requests.exceptions.ConnectionError("Can't connect to dictionary website: http://www.thefreedictionary.com/{}, HTTP code {}".format(value, res.status_code))
value_re = re.compile(value)
for word in res.text.split():
if "" not in word:
continue
word = word[word.find("") + 4:word.find("")].lower()
if '·' in word:
match = re.match(word.replace('·', ''), value)
if not match:
continue
return word.count('·') + 1
not_founds = ("Word not found in the Dictionary and Encyclopedia.",
"is not available in the general English dictionary")
if any(not_found in res.text for not_found in not_founds):
raise SyntaxError("Can't find word in dictionary: {}".format(value))
return 1
def get_num_syllables_all(words):
syllables = {}
for word in words:
word = word.lower()
if word in syllables:
continue
syllables[word] = get_num_syllables(word)
return syllables
def haiku(words, haiku_form):
# words = "Whitecaps on the bay A broken signboard banging In the April wind".split()
num_syllables = get_num_syllables_all(words)
lines = [[] for _ in range(len(haiku_form))]
count, line = 0, 0
for word in words:
count += num_syllables[word.lower()]
if count > haiku_form[line]:
raise SyntaxError("Not possible to split word at syllable boundary: {}, {}".format(word, syllables))
lines[line].append(word)
if count == haiku_form[line]:
line += 1
count = 0
# validate the haiku
for i, line in enumerate(haiku_form):
sum_line = sum(num_syllables[word] for word in lines[i])
if sum_line > line:
raise SyntaxError("Too many syllables in line {}. Got {}, want {}".format(i, sum_line, line))
elif sum_line < line:
raise SyntaxError("Not enough syllables in line {}. Got {}, want {}".format(i, sum_line, line))
return "\n".join(" ".join(line) for line in lines)
if __name__ == '__main__':
haiku_form = (5, 7, 5)
words = input("Please enter the words to use: ").strip().split()
try:
print(haiku(words, haiku_form))
except SyntaxError as e:
print(e)Code Snippets
import requests
import sys
import re
def get_num_syllables(value):
if value.endswith("ing"):
return get_num_syllables(value[:-3]) + 1
try:
res = requests.get("http://www.thefreedictionary.com/" + value)
except requests.exceptions.ConnectionError as e:
print("Can't connect to dictionary website: http://www.thefreedictionary.com/" + value)
sys.exit(1)
if res.status_code != 200:
raise requests.exceptions.ConnectionError("Can't connect to dictionary website: http://www.thefreedictionary.com/{}, HTTP code {}".format(value, res.status_code))
value_re = re.compile(value)
for word in res.text.split():
if "<h2>" not in word:
continue
word = word[word.find("<h2>") + 4:word.find("</h2>")].lower()
if '·' in word:
match = re.match(word.replace('·', ''), value)
if not match:
continue
return word.count('·') + 1
not_founds = ("Word not found in the Dictionary and Encyclopedia.",
"is not available in the general English dictionary")
if any(not_found in res.text for not_found in not_founds):
raise SyntaxError("Can't find word in dictionary: {}".format(value))
return 1
def get_num_syllables_all(words):
syllables = {}
for word in words:
word = word.lower()
if word in syllables:
continue
syllables[word] = get_num_syllables(word)
return syllables
def haiku(words, haiku_form):
# words = "Whitecaps on the bay A broken signboard banging In the April wind".split()
num_syllables = get_num_syllables_all(words)
lines = [[] for _ in range(len(haiku_form))]
count, line = 0, 0
for word in words:
count += num_syllables[word.lower()]
if count > haiku_form[line]:
raise SyntaxError("Not possible to split word at syllable boundary: {}, {}".format(word, syllables))
lines[line].append(word)
if count == haiku_form[line]:
line += 1
count = 0
# validate the haiku
for i, line in enumerate(haiku_form):
sum_line = sum(num_syllables[word] for word in lines[i])
if sum_line > line:
raise SyntaxError("Too many syllables in line {}. Got {}, want {}".format(i, sum_line, line))
elif sum_line < line:
raise SyntaxError("Not enough syllables in line {}. Got {}, want {}".format(i, sum_line, line))
return "\n".join(" ".join(line) for line in lines)
if __name__ == '__main__':
haiku_form = (5, 7, 5)
words = input("Please enter the words to use: ").strip().split()
try:
print(haiku(words, haiku_form))
except SyntaxError as e:
print(e)Context
StackExchange Code Review Q#141323, answer score: 2
Revisions (0)
No revisions yet.