Books full of nonsense: Identify limericks As we all know, limericks are  short, five-line, occasionally-lewd poems with an AABBA rhyming scheme and an anapestic meter (whatever that is):


  Writing a Limerick's absurd
  Line one and line five rhyme in word
  And just as you've reckoned
  They rhyme with the second
  The fourth line must rhyme with the third


You are tasked to write the shortest program that, when fed an input text, prints whether it thinks that the input is a valid limerick. Input can either be on the command line or through standard input, at your option, and output could either be a simple "Y"/"N" or a confidence score, again at your option.

Here's another example of a correct limerick:


  There was a Young Lady whose eyes
  Were unique as to colour and size
  When she opened them wide
  People all turned aside
  And started away in surprise


But the poem below is clearly not a limerick, since it doesn't rhyme:


  There was an old man of St. Bees
  Who was stung in the arm by a wasp.
  When asked, "Does it hurt?"
  He replied, "No, it doesn't,
  I'm so glad that it wasn't a hornet."  


Nor is this one, as the meter is all wrong:


  I heard of a man from Berlin
  Who hated the room he was in
  When I asked as to why
  He would say with a sigh:
  "Well, you see, last night there were a couple of hoodlums around who were celebrating the Bears winning the darned World Cup, and they were really loud so I couldn't sleep because of the din."


Clues

Here are some of the clues you could use to decide whether or not your input is a limerick:


Limericks are always five lines long.
Lines 1, 2 and 5 should rhyme.
Lines 3 and 4 should rhyme.
Lines 1, 2 and 5 have around 3x3=9 syllables, while the third and fourth have 2x3=6 syllables


Note that none of these except the first are hard-and-fast: a 100% correctness rating is impossible.

Rules


Your entry should at the very least correctly categorize examples 1 through 3 in a deterministic fashion.
You are allowed to use any programming language you would like, except of course programming languages specifically designed for this contest (see here).
You are not allowed to use any library except your programming language's standard offerings.
You are allowed to assume that this file, the CMU Sphinx pronounciation dictionary, is in a file called 'c' in the current directory.
You are not allowed to hard-code for the test inputs: your program should be a general limerick categorizer.
You are allowed to assume that the input is ASCII, without any special formatting (like in the examples), but your program should not be confused by interpunction.


Bonuses

The following bonuses are available:


Your program outputs its result as a limerick? Subtract 150 characters length bonus!
Your program also correctly identifies sonnets? Subtract 150 characters extra length bonus!
Your program outputs its result as a sonnet when used on a sonnet? Subtract 100 characters additional extra length bonus!


Finally...

Remember to mention which bonuses you think you deserve, if any, and subtract the bonus from your number of characters to arrive at your score. This is a code golf contest: the shortest entry (i.e. the entry with the lowest score) wins. 

If you need more (positive) test data, check out the OEDILF or the Book of Nonsense. Negative test data should be easy to construct.

Good luck!
Python: 400 - 150 - 150 = 100

The shortest script I could come up with is that one...

import re,sys;f,e,c=re.findall,lambda l,w:f('^'+w.upper()+'  (.+)',l),lambda*v:all([a[i]==a[v[0]]for i in v]);a=[sum([[e(l,w)[0].split()for l in open('c')if e(l,w)][0]for w in f(r'\w+',v)],[])[-2:]for v in sys.stdin];n=len(a);print n==14and c(0,3,4,7)*c(1,2,5,6)*c(8,11)*c(9,12)*c(10,13)*"Sonnet"or"For a critic\nOf limerick\nWell-equipped\nIs this script.\n%s limerick!"%(n==5and c(0,1,4)and c(2,3))


...but don't even try it. It parses the provided dictionary for every word it meets, thus being very slow. Also, an error is generated whenever a word is not in the dictionary.

The code still meets the requirements though: recognizing whether the text passed via stdin is a limerick, a sonnet, or neither of those. 

With only 20 more characters, here is the optimized version:

import re,sys;f,e,c=re.findall,lambda l:f(r'^(\w+)  (.+)',l),lambda*v:all([a[i]==a[v[0]]for i in v]);d={e(l)[0][0]:e(l)[0][1].split()for l in open('c')if e(l)};a=[sum([d.get(w.upper(),[])for w in f(r'\w+',v)],[])[-2:]for v in sys.stdin];n=len(a);print n==14and c(0,3,4,7)*c(1,2,5,6)*c(8,11)*c(9,12)*c(10,13)*"Sonnet"or"For a critic\nOf limerick\nWell-equipped\nIs this script.\n%s limerick!"%(n==5and c(0,1,4)and c(2,3))


Features


able to recognize sonnets (-150)
answers to limericks with a limerick (-150)
relatively fast: only one file parsing per execution


Usage

cat poem.txt | python poem-check.py


3 different outputs are possible:


a limmerick saying the input is one if it is the case
a limmerick saying the input is not one if it is the case
"Sonnet" if the input is recognized as such


Expanded code with explanations

import re, sys

# just a shortened version of the 're.findall' function...
f = re.findall
# function used to parse a line of the dictionary
e = lambda l:f(r'^(\w+)  (.+)', l)

# create a cache of the dictionary, where each word is associated with the list of phonemes it contains
d = {e(l)[0][0]:e(l)[0][1].split(' ') for l in open('c') if e(l)}

# for each verse (line) 'v' found in the input 'sys.stdin', create a list of the phoneme it contains;
# the result array 'a' contains a list, each item of it corresponding to the last two phonemes of a verse
a = [sum([d.get(w.upper(), []) for w in f(r'\w+',v)],[])[-2:] for v in sys.stdin]

# let's store the length of 'a' in 'n'; it is actually the number of verses in the input
n = len(a)
# function used to compare the rhymes of the lines which indexes are passed as arguments
c = lambda*v:all([a[i] == a[v[0]] for i in v])

# test if the input is a sonnet, aka: it has 14 verses, verses 0, 3, 4 and 7 rhyme together, verses 1, 2, 5 and 6 rhyme together, verses 8 and 11 rhyme together, verses 9 and 12 rhyme together, verses 10 and 13 rhyme together
if n==14 and c(0,3,4,7) and c(1,2,5,6) and c(8,11) and c(9,12) and c(10,13):
    print("Sonnet")
else:
    # test if the input is a limerick, aka: it has 5 verses, verses 0, 1 and 4 rhyme together, verses 2 and 3 rhyme together
    is_limerick = n==5 and c(0,1,4) and c(2,3)
    print("For critics\nOf limericks,\nWell-equipped\nIs this script.\n%s limerick!", is_limmerick)