Question

I have a Perl application that takes from command line an input as:

application --fields 1-6,8

I am required to display the fields as requested by the user on command line.

I thought of substituting '-' with '..' so that I can store them in array e.g.

$str = "1..15,16" ;
@arr2 = ( $str ) ;
@arr = ( 1..15,16 ) ;
print "@arr\n" ;
print "@arr2\n" ;

The problem here is that @arr works fine ( as it should ) but in @arr2 the entire string is not expanded as array elements.

I have tried using escape sequences but no luck.

Can it be done this way?

Was it helpful?

Solution

If this is user input, don't use string eval on it if you have any security concerns at all.

Try using Number::Range instead:

 use Number::Range;

 $str = "1..15,16" ;
 @arr2 = Number::Range->new( $str )->range;
 print for @arr2;

To avoid dying on an invalid range, do:

 eval { @arr2 = Number::Range->new( $str )->range; 1 } or your_error_handling

There's also Set::IntSpan, which uses - instead of ..:

 use Set::IntSpan;

 $str = "1-15,16";
 @arr2 = Set::IntSpan->new( $str )->elements;

but it requires the ranges to be in order and non-overlapping (it was written for use on .newsrc files, if anyone remembers what those are). It also allows infinite ranges (where the string starts -number or ends number-), which the elements method will croak on.

OTHER TIPS

You're thinking of @arr2 = eval($str); Since you're taking input and evaluating that, you need to be careful. You should probably @arr2 = eval($str) if ($str =~ m/^[0-9.,]+$/)

P.S. I didn't know about the Number::Range package, but it's awesome. Number::Range ftw.

I had the same problem in dealing with the output of Bit::Vector::to_Enum. I solved it by doing:

$range_string =~ s/\b(\d+)-(\d+)\b/expand_range($1,$2)/eg;

then also in my file:

sub expand_range
{
    return join(",",($_[0] .. $_[1]));
}

So "1,3,5-7,9,12-15" turns into "1,3,5,6,7,9,12,13,14,15".

I tried really hard to put that expansion in the 2nd part of the s/// so I wouldn't need that extra function, but I couldn't get it to work. I like this because while Number::Range would work, this way I don't have to pull in another module for something that should be trivial.

@arr2 = ( eval $str ) ;

Works, though of course you have to be very careful with eval().

You could use eval:

$str = "1..15,16" ;
@arr2 = ( eval $str ) ;
@arr = ( 1..15,16 ) ;
print "@arr\n" ;
print "@arr2\n" ;

Although if this is user input, you'll probably want to do some validation on the input string first, to make sure they haven't input anything dodgy.

Use split:

@parts = split(/\,/, $fields);

print $parts[0];
1-6
print $parts[1];
8

You can't just put a string containing ',' in an array, and expect it to turn to elements (except if you use some Perl black magic, but we won't go into that here)

But Regex and split are your friends.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top