daverave has asked for the wisdom of the Perl Monks concerning the following question:

Hello,

I would like to use a string (e.g. read from a file) as a piece of code in my perl program. For example, I read a string (e.g. $str="1..100,171,398..1000") then I would like to print all the numbers in the range represented by the string.

Thanks, Dave

Replies are listed 'Best First'.
Re: use string as a piece of code
by moritz (Cardinal) on Jul 30, 2010 at 16:49 UTC
    It seems that Set::IntSpan can solve your problem without eval, provided you substitute the .. by - first.
    Perl 6 - links to (nearly) everything that is Perl 6.
Re: use string as a piece of code
by SuicideJunkie (Vicar) on Jul 30, 2010 at 16:53 UTC

    You would be better served to parse that, and then do the loop, rather than just evaling arbitrary strings that may include Bobby Tables, or rm -rf *

    I suggest a series of simple regex:

    1. Remove everything that is not a digit, a comma or a '..'
    2. clean up leading/trailing commas and multiple commas in a row
    3. Validate (everything should in the expected form (number {comma or EOS}, or number dot-dot number {comma or EOS})
    4. split on commas
    5. For each item in the split, capture some digits followed by an optional '..' with more captured digits afterwards
    6. If there wasn't a '..', then just print $1, other wise, print $_ for $1..$2

    - SJ

    How to make perldoc.perl.org resizable too!
    The monks can fry your fish, and they can give you some tips and some bait, but you still need to wake up in the morning and climb onto the boat.
Re: use string as a piece of code
by FunkyMonk (Bishop) on Jul 30, 2010 at 16:45 UTC
    eval.

    my $str = '1..3,10..14'; do_something($_) for eval $str;

    Just be very sure that you trust whoever created the file you're reading from. What happens if it contains "system qw{rm -rf /}" (or the equivalent on your OS)?

    update: Added code

      Thanks!

      A followup: my ranges are quite large (~500k numbers, usually in one or two blocks only, i.e. something like 1..20000,700000..1000000).

      What is the efficient way to simply print them out to a file?

      Maybe  for $i (1..20000,700000..1000000) {print "$i "}? I'm not sure if an array is actually created here... if it is, maybe it's not a good idea.