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

Hello,

This seems like somthing I should know and have probably
come across before, but I'm tired of thinking.


Thanks for your help in advanced!
#!/usr/bin/perl use strict; my @ranges = (2..5,10..15); my $range = "2..5,10..15"; my $schoolID = "234"; my $teacherID = "1001"; my $fields = "StID,SchooldID,TeacherID,KnowPre,KnowPost,Prefact"; # start sheet creation print "$fields\n"; foreach my $stID (@ranges) { print "$stID,$schoolID,$teacherID,,,\n"; } foreach my $stID (@{[$range]}) { print "$stID,$schoolID,$teacherID,,,\n"; }

2005-10-10 Retitled by planetscape, as per Monastery guidelines
Original title: 'Irritate string like, for(1..5) i.e. $stirng="1..5"; for($string)'

Replies are listed 'Best First'.
Re: Iterate string like, for(1..5) i.e. $stirng="1..5"; for($string) (lazy)
by tye (Sage) on Oct 10, 2005 at 03:57 UTC

    Note that for($x..$y) is optimized to be lazy but that isn't true for for(eval"$x..$y"). For example:

    $ perl $x=1<<30; for(1..$x){last;} warn "first"; for(eval "1..$x"){last;} warn "second"; __END__ first at - line 3. core dumped

    The for(1..$x) very quickly tries $_=1 and then exits the loop. The for(eval "1..$x") doesn't even run because it tries to build the entire "1..1<<30" list in memory before it can get started and it runs out of memory and dumps core before then.

    Just something to keep in mind.

    - tye        

Re: Iterate string like, for(1..5) i.e. $stirng="1..5"; for($string)
by Aristotle (Chancellor) on Oct 10, 2005 at 01:49 UTC

    Ok, now that your question was answered with the use of eval, can you tell us why you want to do that? It is very likely that what you want to do is not the best way to go about it (for many, many reasons), and if you tell us a little more, someone might suggest a better approach for solving your specific task.

    Makeshifts last the longest.

      I would be happy to explain more,
      I am getting input from a CGI query, $cgi->query('range')
      the input will look like 1..50,60,100..150 This would probably very much fall under a great
      reason why not to use eval for this.

      This is what I want to do
      #snip my $range = $cgi->param('range'); for (eval "($range)") { # Is there a better way? print "$_\n"; }

      Thanks again,
      gman

        Indeed, that’s a scenario where you really really don’t want to use eval.

        How constrained is the format? If sufficiently so, how about parsing the input manually? Assuming the dots and commata are the only “metacharacters”, you could do something like this:

        my @range = map { m{ (\d+) \s* \.\. \s* (\d+) }msx ? $1 .. $2 : /(\d+)/ } split /,/, $range;

        This breaks the string apart at the commata, then tries to match something that looks like a range; if it succeeds then it uses the regular range operator to make a real range out of it. If it fails, it returns the first sequence of digits it finds.

        It should work correctly for any combination of ranges and single numbers strung together with commata. It’s also pretty lenient and will accept whitespace within ranges and any sort of non-digit garbage everywhere else – that might not be what you want, or might be just fine. Your call.

        It will also not work for negative numbers and for fractional components. If you need to match more than just positive integers, the quickest and most robust way is probably to employ Regexp::Common.

        Makeshifts last the longest.

Re: Iterate string like, for(1..5) i.e. $stirng="1..5"; for($string)
by YuckFoo (Abbot) on Oct 10, 2005 at 02:34 UTC
    I would rather use a variable for each part of the range instead of trying to represent the whole range as a string to be evalled.

    Yuck..Foo

    #!/usr/bin/perl use strict; my $beg = 1; my $end = 5; for my $i ($beg..$end) { print "$i\n"; }
Re: Iterate string like, for(1..5) i.e. $stirng="1..5"; for($string)
by jkeenan1 (Deacon) on Oct 10, 2005 at 01:30 UTC
    Your program compiles, runs and produces this output:

    And your question is .... ?

Re: Iterate string like, for(1..5) i.e. $stirng="1..5"; for($string)
by GrandFather (Saint) on Oct 10, 2005 at 01:15 UTC

    But what is the question? What do you expect to see printed?


    Perl is Huffman encoded by design.
      I would like my output to be the same using as
      explecit for(1..5) or a string in it's place for($string)
      where $string = "1..5";
      Thanks

        Do you want something like:

        my $range = "2..5,10..15"; my @ranges = eval "($range)";

        Perl is Huffman encoded by design.
Re: Iterate string like, for(1..5) i.e. $stirng="1..5"; for($string)
by schwern (Scribe) on Oct 11, 2005 at 06:15 UTC
    my $range = "2..5,10..15"; # Split on commas my @range = split /,/, $range; # Expand any n..m @range = map { /(\d+)..(\d+)/ ? ($1..$2) : $_ } @range;

    Assuming the resulting @range is small (where small is, say, less than 10,000 elements) this will do fine. Error checking is left as an exercise for the reader.