

 This page uses content from Wikipedia. The original article was at Mad Libs. The list of authors can be seen in the page history. As with Rosetta Code, the text of Wikipedia is available under the GNU FDL. (See links for details on variance)


Mad Libs is a phrasal template word game where one player prompts another for a list of words to substitute for blanks in a story, usually with funny results.



Task;
Write a program to create a Mad Libs like story.

The program should read an arbitrary multiline story from input.

The story will be terminated with a blank line.

Then, find each replacement to be made within the story, ask the user for a word to replace it with, and make all the replacements.

Stop when there are none left and print the final story.



The input should be an arbitrary story in the form:

<name> went for a walk in the park. <he or she>
found a <noun>. <name> decided to take it home.

Given this example, it should then ask for a name, a he or she and a noun (<name> gets replaced both times with the same value).




Other tasks related to string operations:

Metrics
 Array length
 String length
 Copy a string
 Empty string  (assignment)
Counting
 Word frequency
 Letter frequency
 Jewels and stones
 I before E except after C
 Bioinformatics/base count
 Count occurrences of a substring
 Count how many vowels and consonants occur in a string
Remove/replace
 XXXX redacted
 Conjugate a Latin verb
 Remove vowels from a string
 String interpolation (included)
 Strip block comments
 Strip comments from a string
 Strip a set of characters from a string
 Strip whitespace from a string -- top and tail
 Strip control codes and extended characters from a string
Anagrams/Derangements/shuffling
 Word wheel
 ABC problem
 Sattolo cycle
 Knuth shuffle
 Ordered words
 Superpermutation minimisation
 Textonyms (using a phone text pad)
 Anagrams
 Anagrams/Deranged anagrams
 Permutations/Derangements
Find/Search/Determine
 ABC words
 Odd words
 Word ladder
 Semordnilap
 Word search
 Wordiff  (game)
 String matching
 Tea cup rim text
 Alternade words
 Changeable words
 State name puzzle
 String comparison
 Unique characters
 Unique characters in each string
 Extract file extension
 Levenshtein distance
 Palindrome detection
 Common list elements
 Longest common suffix
 Longest common prefix
 Compare a list of strings 
 Longest common substring
 Find common directory path
 Words from neighbour ones
 Change e letters to i in words
 Non-continuous subsequences
 Longest common subsequence
 Longest palindromic substrings
 Longest increasing subsequence
 Words containing "the" substring
 Sum of the digits of n is substring of n
 Determine if a string is numeric
 Determine if a string is collapsible
 Determine if a string is squeezable
 Determine if a string has all unique characters
 Determine if a string has all the same characters
 Longest substrings without repeating characters
 Find words which contains all the vowels
 Find words which contains most consonants
 Find words which contains more than 3 vowels
 Find words which first and last three letters are equals
 Find words which odd letters are consonants and even letters are vowels or vice_versa
Formatting
 Substring
 Rep-string
 Word wrap
 String case
 Align columns
 Literals/String
 Repeat a string
 Brace expansion
 Brace expansion using ranges
 Reverse a string
 Phrase reversals
 Comma quibbling
 Special characters
 String concatenation
 Substring/Top and tail
 Commatizing numbers
 Reverse words in a string
 Suffixation of decimal numbers
 Long literals, with continuations 
 Numerical and alphabetical suffixes
 Abbreviations, easy
 Abbreviations, simple
 Abbreviations, automatic
Song lyrics/poems/Mad Libs/phrases
 Mad Libs
 Magic 8-ball
 99 Bottles of Beer
 The Name Game (a song)
 The Old lady swallowed a fly
 The Twelve Days of Christmas
Tokenize
 Text between
 Tokenize a string
 Word break problem
 Tokenize a string with escaping
 Split a character string based on change of character
Sequences
 Show ASCII table
 De Bruijn sequences
 Self-referential sequences
 Generate lower case ASCII alphabet




# Mad Libs style story generation                                        #
 
# gets the story template from the file f. The template terminates with  #
# a blank line                                                           #
# The user is then promoted for the replacements for the <word> markers  #
# and the story is printed with the substitutions made                   #
PROC story = ( REF FILE f )VOID:
BEGIN
 
    # a linked list of strings, used to hold the story template          #
    MODE STRINGLIST = STRUCT( STRING text, REF STRINGLIST next );
 
    # a linked list of pairs of strings, used to hold the replacements   #
    MODE REPLACEMENTLIST = STRUCT( STRING word
                                 , STRING replacement
                                 , REF REPLACEMENTLIST next
                                 );
 
    # NIL reference for marking the end of a STRINGLIST                  #
    REF STRINGLIST      nil stringlist      = NIL;
 
    # NIL reference for marking the end of a REPLACEMENTLIST             #
    REF REPLACEMENTLIST nil replacementlist = NIL;
 
 
    # returns "text" with trailing spaces removed                        #
    OP RTRIM = ( STRING text )STRING:
    BEGIN
        INT trim pos := UPB text;
        FOR text pos FROM UPB text BY -1 TO LWB text WHILE text[ text pos ] = " "
        DO
            trim pos := text pos - 1
        OD;
 
        text[ LWB text : trim pos ]
    END; # RTRIM #
 
    # looks for word in the dictionary. If it is found, replacement is   #
    # set to its replacement and TRUE is returned. If word not present,  #
    # FALSE is returned - uses recursion                                 #
    PROC find replacement = ( STRING word
                            , REF STRING replacement
                            , REF REPLACEMENTLIST dictionary
                            )BOOL:
        IF   dictionary IS nil replacementlist
        THEN
            FALSE
        ELIF word OF dictionary = word
        THEN
            replacement := replacement OF dictionary;
            TRUE
        ELSE
            find replacement( word, replacement, next OF dictionary )
        FI; # find replacement #
 
 
    # read the story template                                            #
 
    # the result has a dummy element so "next OF next" is always valid   #
    REF STRINGLIST     story := HEAP STRINGLIST := ( "dummy", nil stringlist );
    REF REF STRINGLIST next  := story;
 
    # read the story template, terminates with a blank line              #
 
    WHILE
        STRING text;
        get( f, ( text, newline ) );
        text := RTRIM text;
        text /= ""
    DO
        # add the line to the end of the list #
        next := ( next OF next ) := HEAP STRINGLIST := ( text, nil stringlist )
    OD;
 
    # find the <word> markers in the story and replace them with the     #
    # user's chosen text - we ignore the dummy element at the start      #
 
    REF REPLACEMENTLIST dictionary := nil replacementlist;
    REF STRINGLIST      line       := story;
 
    WHILE line := next OF line;
          line ISNT nil stringlist
    DO
        # have a line of text - replace all the <word> markers in it     #
        STRING word, replacement;
        INT start pos, end pos;
        WHILE char in string( "<", start pos, text OF line )
          AND char in string( ">", end pos,   text OF line )
        DO
            # have a marker, get it from the line                        #
            word := ( text OF line )[ start pos : end pos ];
            # get its replacement                                        #
            IF NOT find replacement( word, replacement, dictionary )
            THEN
                # we don't already have a replacement for word           #
                # get one from the user and add it to the dictionary     #
                print( ( "What should replace ", word, "? " ) );
                read( ( replacement, newline ) );
                dictionary := HEAP REPLACEMENTLIST := ( word, replacement, dictionary )
            FI;
            # replace <word> with the replacement                        #
            text OF line := ( text OF line )[ : start pos - 1 ]
                          + replacement
                          + ( text OF line )[ end pos + 1 : ]
        OD
    OD;
 
    # print the story, ignoring the dummy element at the start           #
 
    line := story;
 
    WHILE line := next OF line;
          line ISNT nil stringlist
    DO
        print( ( text OF line, newline ) )
    OD
 
END; # story #
 
main:(
 
    # we read the template from stand in (the keyboard unless it's been  #
    # redirected) we could prompt the user for a template file name,     #
    # open it and read that instead...                                   #
    print( ( "Please Enter the story template terminated by a blank line", newline ) );
    story( stand in )
 
)