A recent posting by MrCromeDome showed a quick CUFP-type script to generate random silliness, presumably to badger cow-orkers. Being in a refactoring mood, I thought that it might be better if you could describe your "remark" in a text file. This would be used as a template for generating messages, not unlike your typical "mad-lib". Since it's just a text file, it can be edited by mere mortals without fear of compilation errors.

In this file, there would be two kinds of replacements: Automatic, where a word is picked from a list of possibilities, and prompted, where the user has to answer a question. Here's an example which incorporates both types using a very basic tagging system:
When I was walking down the [street|boulevard|avenue] a large [squirrel|frog|lemur|llama] [leaped|jumped|ran|crawled] out and [bit|mauled|chewed|spit at] me! You'd never believe what [Name?] said!
When this is run, you'd see something that looks like this, plus or minus input and random factors:
% perl madlib sample.madlib Name? George Jetson When I was walking down the avenue a large llama jumped out and bit me! You'd never believe what George Jetson said!
If you're probably thinking this is a couple of simple regexes, you're not entirely wrong. However, to spice things up, there's a few "rules" about how the program runs: As food for thought, here's my first take at 159 characters, not including linebreaks to suppress the red plus marks:
select STDERR;$|++;select STDOUT;$_=join('',<>); s#\[([^\]]*\?)\]#print STDERR"$1 ";chomp($i=<STDIN>);$i#ge; s#\[([^\]]*)\]#@f=split(/\|/,$1);$f[rand@f]#ge;print

Replies are listed 'Best First'.
Re: (Golf) Mad-Lib Generator
by abstracts (Hermit) on Jul 17, 2002 at 03:59 UTC
    Here is my trial at 112. Basically, I joined the 2 substitutions in one, removed unneeded parens, used chop instead of chomp. The regex looks pretty confusing though.

    Remeber, STDERR is unbuffered, so no need to $|++ it.

    $_=join'',<>;s#\[([^\]]*?(\?)?)\]#$2?do{print STDERR"$1 "; $_=<>;chop;$_}:do{@f=split/\|/,$1;$f[rand@f]}#ge;print
    Update: removed STDIN.
Re: (Golf) Mad-Lib Generator
by japhy (Canon) on Jul 17, 2002 at 16:21 UTC
    Here's mine. 103 chars.
    $_=join'',<>;s!\[(.*?)(\??)]!$2?print(STDERR"$1? ") &&(<>=~/.*/g)[0]:split('\|',$1)&&$_[rand@_]!eg;print

    _____________________________________________________
    Jeff[japhy]Pinyan: Perl, regex, and perl hacker, who'd like a job (NYC-area)
    s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

Re: (Golf) Mad-Lib Generator
by Util (Priest) on Jul 17, 2002 at 16:07 UTC
    100 characters:
    print map{ if(s/\?$/? /){print STDERR;$_=<STDIN>;chop} @z=split/\|/;$z[rand@z] }map{split/\[(.+?)\]/}<>

    Explanation:
    Using split, transform all the lines of input into a list of "chunks"; each chunk is

    • plain text, or
    • bracketed text with the brackets removed.
    For each chunk:
    1. If it ends in '?', then append a space to it, print it to STDERR, and replace it with the chomped/chopped input.
    2. Split it on '|' into an array, and select a random element from the array. If there is no '|' in the chunk, then the array contains the entire chunk in one element, and that element will always be "randomly" chosen.
    Since the random selection occurs last in the map, its value is passed on to print for each chunk.

    Notes:

    1. I beat my head against 101, until I s/chomp/chop/.
    2. Nothing was said about newline normalization, so I could remove the chop.
    3. In real golf, there would probably be a test case with '|' and trailing-'?' in non-bracketed text, which my program would fail to handle correctly.

    Update: Forced "read all ARGV and close" with "@_=<>". This allowed me to change "<STDIN>" to "<>".
    98 characters:

    print map{if(s/\?$/? /){print STDERR;$_=<>;chop}@z=split/\|/;$z[rand@z +]}map{split/\[(.+?)\]/}@_=<>

Re: (Golf) Mad-Lib Generator
by vladb (Vicar) on Jul 17, 2002 at 04:14 UTC
    157 characters... ;-)
    select *I=*STDERR;$|++;select STDOUT;$_=join('',<DATA>); s#\[([^\]]*\?)\]#print I"$1 ";chomp($i=<DATA>);$i#ge; s#\[([^\]]*)\]#@f=split(/\|/,$1);$f[rand@f]#ge;print


    Update: admittadly, I suck at golf ;/

    Yet, just now I've learnt an important lesson. The only reason I failed to produce significantly shorter/improved golf code is because I simply failed to think 'outside of the box'. For a couple minutes I simply kept staring at the initial golf piece, in the back of my mind being afraid to temper with it too much as not to break it.

    Had I only taking the logic of the code aside and tried to come up with an alternative code of mine, I could have a better chance at gaining significant improvement.

    {grin}

    Update 1:

    Looking at Util's and japhy's golf code and sort of combining the good parts of both, I get this piece 97 characters long:
    print map{s/\?$/? /?print(STDERR)&&(<>=~/.*/g)[0]:split('\|')&&$_[rand +@_]} map{split/\[(.+?)\]/}<>


    Update 2:

    japhy, the golf works fine for me, here's the complete code and source file:
    #!/usr/local/bin/perl print map{s/\?$/? /?print(STDERR)&&(<>=~/.*/g)[0]:split('\|')&&$_[rand +@_]} map{split/\[(.+?)\]/}<>
    Source file:
    Hello [world|planet|dude|there], [Name?]!
    Hmm,.. but it does appear to print extra '0's when I use the original text. Let me investigate why that's the case ... update: This works:
    print map{if(s/\?$/? /){print STDERR;(<>=~/.*/g)[0]}@z=split/\|/;$z[ra +nd@z]} map{split/\[(.+?)\]/}<>


    _____________________
    # Under Construction
      I get zeroes in the output when I use this.

      _____________________________________________________
      Jeff[japhy]Pinyan: Perl, regex, and perl hacker, who'd like a job (NYC-area)
      s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

Re: (Golf) Mad-Lib Generator
by japhy (Canon) on Jul 17, 2002 at 15:44 UTC
    How bizarre. I was thinking of writing one last night. I'll post my golf here soon.

    _____________________________________________________
    Jeff[japhy]Pinyan: Perl, regex, and perl hacker, who'd like a job (NYC-area)
    s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??;

•Re: (Golf) Mad-Lib Generator
by merlyn (Sage) on Jul 17, 2002 at 21:40 UTC
Re: (Golf) Mad-Lib Generator
by MrCromeDome (Deacon) on Jul 17, 2002 at 13:15 UTC
    Excellent post. . . ++ to you =) You spelled my name incorrectly though ;) MrCromeDome, not MrChromeDome (no H in it ;)

    MrCromeDome