[madlibBest1] Start with main: def main(): words = [] #Here are all the types of fillers you can use to create your madlib posTypes = ['NOUN','NOUN (PLURAL)','PLACE','ADJECTIVE'] posTypes += ['VERB (SINGULAR SUBJECT)','VERB (PLURAL SUBJECT)','NUMBER','BODY PART'] # Create your form. # Include all spaces in the strings which you want on the output # 'DET' means that a or an should be printed before the next word. # NewLine is just a human-friendly signal that you want a '\n' # form = 'Be kind to your NOUN-footed NOUN (PLURAL). NEWLINE' form += "For a duck may be somebody's NOUN. NEWLINE" form += 'Be kind to your NOUN in PLACE, NEWLINE' form += 'For they may be DET NOUN' words = inputWords(posTypes,form) generateMadLib(posTypes,form,words) main() This is the function that asks the user for the fillers. E.g., NOUN in NOUN-footed and so on. def inputWords(posTypes,form): words = [] while form: posType = startsWithPosType(posTypes,form) if posType: words.append(input(posType + ' ')) form = form.lstrip(posType) else: form = form[1:] return words form is a string, remember. startsWithPOSType(posTypes,form) e.g., form = 'Be kind to your NOUN-footed NOUN (PLURAL) ....' startsWithPosType(posTypes,form) returns False, since form does not start with any of the posTypes. So, if posType is FALSE. We go into the else clause. form is now: 'e kind to your NOUN-footed NOUN (PLURAL) ....' startsWithPosType(posTypes,form) posType is False form is updated to: ' kind to your NOUN-footed NOUN (PLURAL) ....' This continues - call to startwWithPosType; returns None; go to the else clause. finally, form will be: form: 'NOUN-footed NOUN (PLURAL) ....' startsWithPosType returns 'NOUN' - the longest member of posTypes The test is true: if posType: words.append(input(posType + ' ')) form = form.lstrip(posType) NOUN - will appear on the screne user will enter a noun, say 'banana' words = ['banana'] help(str.lstrip) lstrip(...) S.lstrip([chars]) -> str Return a copy of the string S with leading whitespace removed. If chars is given and not None, remove characters in chars instead. So, this will remove NOUN from the LEFT removed. form is now '-footed NOUN (PLURAL) ....' and the process continues. when we are done, we will have the list of words that fill the form. E.g., ['banana','cats','dog','computer','tree','Omaha','hat'] form = 'Be kind to your NOUN-footed NOUN (PLURAL). NEWLINE' form += "For a duck may be somebody's NOUN. NEWLINE" form += 'Be kind to your NOUN in PLACE, NEWLINE' form += 'For they may be DET NOUN' def startsWithPosType(posTypes,s): ''' Return the longest posType with which s starts. Return the empty string if s does not start with any posType''' # This way, we don't have to bother the user to worry about ordering # the strings in posTypes match = '' for p in posTypes: if s.startswith(p): if len(p) > len(match): match = p return match p is first 'NOUN', then 'NOUN (PLURAL)', etc. posTypes = ['NOUN','NOUN (PLURAL)','NOUN','NOUN','PLACE','NOUN','ADJECTIVE'] posTypes += ['VERB (SINGULAR SUBJECT)','VERB (PLURAL SUBJECT)','NUMBER','BODY PART'] Remember: we have "NOUN" and "NOUN (PLURAL)" When the form has NOUN (PLURAL) we want to ask the user for that. NOT for the shorter "NOUN". So, we want to find the LONGEST match in the posTypes. Remember, last time we looked in a dictionary for a particle that has the lowest probability. We are going to do something similar here - we want to remember and keep the longest matching string!!! we will keep it in "match". we want to start with 'match' having a worse value than anything we will find. last time: we started with leastval being greater than 1 - that will be higher than any probability we will find. Here, since we are looking for the longest string, start with the empty string! that's shorter than any match we will find! If you find a match, - here p - then if it is longer than any match you found so far (or, the initial value of ""), then keep it. starting at "" also means we handle the case where there is no match. So, suppose we have gotten to this point: form = 'NOUN (PLURAL). NEWLINE ...' p NOUN NOUN (PLURAL) match NOUN NOUN (PLURAL) we had this little function: def det(noun): if noun[0] in 'aeiou': return 'an' else: return 'a' Now, the main function! Create the string, and output it. def generateMadLib(posTypes,form,words): s = '' i = 0 while form: if form.startswith('NEWLINE'): s += '\n' form = form.lstrip('NEWLINE') elif form.startswith('DET'): s += det(words[i]) form = form.lstrip('DET') elif startsWithPosType(posTypes,form): posType = startsWithPosType(posTypes,form) if posType: # We have come to a posType: add the next word, and # remove the filler from the form s += words[i] i += 1 form = form.lstrip(posType) else: # No special cases; just add the next character # to the output string, and remove it from form s += form[0] form = form[1:] print(s) form = 'Be kind to your NOUN-footed NOUN (PLURAL). NEWLINE' form += "For a duck may be somebody's NOUN. NEWLINE" form += 'Be kind to your NOUN in PLACE, NEWLINE' form += 'For they may be DET NOUN' Up until we hit NOUN, we drop the first char of form, and add it to the string s: i 0 s = "Be kind to your " form = NOUN-footed NOUN (PLURAL)...." Now, startsWithPosType will return NOUN words[i] is banana; we add that to the string! add one to i, since we've taken care of 'banana' remove "NOUN" from form. i 1 s = "Be kind to your banana" form = '-footed NOUN (PLURAL)...." then, the "else" will be executed until we read NOUN (PLURAL) i 1 s = "Be kind to your banana-footed " form = 'NOUN (PLURAL). NEWLINEFor a duck...' words[1] is dogs i 2 s = "Be kind to your banana-footed dogs" form = '. NEWLINEFor a duck...' etc