Ruby, 8618 correct (91.1%), 53 bytes, 8618 - 10 * 53 = 8088 score
->s{s.scan(/[aiouy]+e*|e(?!d$|ly).|[td]ed|le$/).size}
This is an anonymous Ruby function which uses regexes to count syllables.
The function adds a syllable for every instance of:
- A run of non-
e
vowels, followed by zero of more e
s
- An
e
which is not part of a trailing ed
or ely
, with the exception of trailing ted
or ded
s
- A trailing
le
Analysis
The basic idea is to count runs of vowels, but this by itself isn't very accurate ([aeiouy]+
gets 74% correct). The main reason for this is because of the silent e
, which modifies the previous vowel sound while not being pronounced itself. For example, the word slate
has two vowels but only one syllable.
To deal with this, we take e
out of the first part of the regex and treat it separately. Detecting silent e
s is hard, but I found two cases where they occur often:
- As part of a trailing
ed
(unless it's a ted
or ded
like settled
or saddled
),
- As part of a trailing
evy
(e.g. lovely
)
These cases are specifically excluded in what would otherwise be e.
.
The reason for the .
in e(?!d$|ly).
is to consume the next char if there is a double vowel (e.g. ea
or ee
), and so that e
at the end of the word are not counted. However a trailing le
is usually pronounced, so that is added back in.
Finally, vowel runs are counted as one syllable. While this may not always be the case (e.g. curious
), it's often difficult to work out whether there are multiple syllables. Take the ia
of celestial
and spatial
, as an example.
Test program
I don't really know Ruby so I'm not sure how well it can be golfed. I did manage to scrape together a test program by consulting a lot of SO though:
cases = 0
correct = 0
s = "->s{s.scan(/[aiouy]+e*|e(?!d$|ly).|[td]ed|le$/).size}"
f = eval s
for i in 1 ... 8
filepath = i.to_s + "-syllable-words.txt"
file = File.open(filepath)
while (line = file.gets)
word = line.strip
cases += 1
if f.call(word) == i
correct += 1
end
end
end
p "Correct: #{correct}/#{cases}, Length: #{s.length}, Score: #{correct - s.length*10}"
resume
for example... \$\endgroup\$