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

After the third script I've written that includes a sub to deal with the title issue, I'm thinking there must be a module to do this so I don't have to keep putting the same sub in all my scripts.

I'm looking to pass a command line argument like such (for example):

> progname -c 1,7-10,3-5,15

The code I keep putting into my scripts simply takes the string argument returned from Getopt::Long (GetOptions) - in the above example: "1,7-10,3-5,15" - and expands it to a sorted array: 1 3 4 5 7 8 9 10 15" which I do some stuff with later. Not too complicated, the code I have works and is pretty straigt forward.

I'm just wondering if there is something in Getopt perhaps that I'm not utilizing? I've dome quite a bit of searching, but I'm using terms like "number range" and "expand list of numbers" and I'm not quite getting the hits I want.

So anyone know of a module that does this, or should I just keep pasting my code into each script I write that needs this functionality?

Replies are listed 'Best First'.
Re: Perl Module for dealing with number ranges
by eff_i_g (Curate) on Mar 27, 2009 at 21:32 UTC
    Set::IntSpan

    Update:
    use Set::IntSpan; my $span = Set::IntSpan->new('1,3-5,7-10,15'); print join "\n" => $span->elements();
Re: Perl Module for dealing with number ranges
by linuxer (Curate) on Mar 27, 2009 at 21:35 UTC

    Well, you could have a look at Number::Range. With some adjustments to your syntax, you might use that module?

    If that doesn't fit your needs, why don't you create a module on your own, which provides access to your function? So you won't need to copy your code, but can rely to that module...

Re: Perl Module for dealing with number ranges
by graff (Chancellor) on Mar 27, 2009 at 22:10 UTC
    So anyone know of a module that does this, or should I just keep pasting my code into each script I write that needs this functionality?

    Just in case the first two suggestions above turn out to be less or different than what you really want, you could just take that block of code you keep copying, isolate it into a module of your own, place the module in some path that your standard @INC knows about, and "use YourModule;" in whatever script is going to need it.

    Taking some bit of code and making it work as a stand-alone module is really simpler than you might expect, and is a very handy skill to have. It's the first thing that should come to mind when you find yourself copy/pasting stuff from one script to another.

Re: Perl Module for dealing with number ranges
by Your Mother (Archbishop) on Jun 05, 2009 at 19:40 UTC

    I certainly do not advocate doing it this way. Use one of the modules and reap the benefits of testing, a user base, docs you don't have to write, and future improvements. This is just for fun and because I found dmmiller2k's example a bit hard to read.

    while (<DATA>) { chomp; print join(" + ", expand($_)), $/; } sub expand { my $input = shift; $input =~ s/[^-\d,]+//g; $input =~ s/-/../g; my ( %tmp, @tmp ); @tmp = ( eval "$input" ); @tmp{@tmp} = (1) x @tmp; # dedupe return sort { $a <=> $b } keys %tmp; } __DATA__ 1,7-10,3-5,15 or even ... my $input = "1,7-10,3-5,15";
      mmh. some year is passed, but.. I need to expand coordinate ranges, comma separated like in 4 4 , 5-7 5, 0 0, 0-23 2

      With the help of moritz in the chat and plagiarizing rosetta code I ended with this:
      #!perl use strict; use warnings; my $input = "@ARGV"; my @pairs = split /,/, $input; foreach my $pair (@pairs){ $pair =~ s/^\s+//;$pair =~ s/\s+$//; print map {"->$_\n"} &exp_coord($pair); } sub exp_coord { my ($r,$c)=split /\s/,"@_"; unless (defined $r and defined $c) {warn "Both must be defined. Re +ceived:",map{defined $_ ? "$_ " : 'UNDEF '}($r,$c);return} my @r; my @c; my @expanded; @r = $r=~/^(.*\d)-(.+)$/ ? ($1..$2) : ($r); @c = $c=~/^(.*\d)-(.+)$/ ? ($1..$2) : ($c); for my $rc (@r) { for my $cc (@c) { push @expanded, "$rc $cc" } }; return @expanded; }
      HtH
      L*
      There are no rules, there are no thumbs..
      Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: Perl Module for dealing with number ranges
by ig (Vicar) on Mar 29, 2009 at 00:23 UTC

    Searching CPAN for number range returns Number::Range at the top of the list and a few other possibilities in the first few pages.

Re: Perl Module for dealing with number ranges
by dmmiller2k (Chaplain) on Jun 05, 2009 at 18:30 UTC

    I recently had this same problem. Not realizing there might be a CPAN module (I know, I know, what was I thinking?), I came up with this sub:

    sub expandlist { local $" = '..'; # locally set list separator my (@parts); sort {$a <=> $b} map { map { ((@parts = split /-/) == 2) ? eval('map {$_} '. "@parts") : $_ } split /,/ } @_; }

    Briefly:

    • The outer map loops through all function args (usually only called with one). For each arg, split on commas.
    • Try to split each element originally separated by commas, on hyphens.
    • If splitting on hyphens produces exactly two elements in @parts, interpolate the array into a string (with the list separator set to '..'), turning, e.g., '6-9' into '6..9' which is appended to 'map {$_}' and that whole thing eval'ed, ultimately producing a list of elements: 6, 7, 8, 9
    • The elements are all gathered and combined and sorted.

    Crude and hardly idiot-proofed, but it works without having to get a CPAN module installed on all our servers.

    dmm

    Procrastinate NOW! Don't put it off... --Ellen Degeneres