Take the 2-minute tour ×

A short question: I want to give users of my script the possibility to enter arbitrary arrays, e.g. "[1 .. 5]" or "[1, 2, 6, 9 .. 20]". Currently, I just eval the given string (obviously not very secure!) and perlcritic gives me a Level 5 warning.

My current code:

my $arr = eval $patternData{"arr"};
unless ($arr) {
     # fixes <arr> values like "(1 .. 5)"
     $arr  = undef;
     @$arr = eval $patternData{"arr"};

EDIT: As many people are asking: This is a "the-more-the-better" thingy. I search a solution both powerful (in terms of expressiveness) and simple (in terms of debugging, parsing and writing input). Also: It absolutely has to support ranges (arrays with well above 100 entries should be entered easily)

and - as always - I forgot to include my version. 5.8 is a must, I'm working with vSphere API, which requires 5.8 (I miss ~~ so much !)

This is perl, v5.8.8 built for MSWin32-x86-multi-thread
(with 50 registered patches, see perl -V for more detail)

Copyright 1987-2006, Larry Wall

Binary build 820 [274739] provided by ActiveState http://www.ActiveState.com
Built Jan 23 2007 15:57:46
share|improve this question
Would arbitrary arrays include things like [ map { ($_, $_+7 ) } split //, q(123)] or how much expressiveness do you really need? –  pmakholm Sep 25 '12 at 8:00
check whether this helps. –  tuxuday Sep 25 '12 at 8:03

2 Answers 2

up vote 4 down vote accepted

How tied are you to your current input format?

One soulution could be to "change" the format to JSON and the use JSON::XS to deserialize your input. [1, 2, 3, 4] would still be valid input, but this would not allow [1, 2, 3, 4, 8 .. 10 ]

In all cases you will of course need to validate that the input data has the correct structure.

share|improve this answer
Another alternative would be to use Parse::Range. This would give you ranges, but will only support a list of integers. (Which might be a plus). –  pmakholm Sep 25 '12 at 8:03
Parse::Range looks pretty good, I'm not sure if it is sufficient (the code is part of a bigger project and the requirements evolve with the project ;) ) but it works as a medium-term solution at least! EDIT: Parse::Range isn't included in ppm :/ –  Megge Sep 25 '12 at 8:50

If your array only allows numbers, I'd opt for this pattern (being easy to parse):

[1, 2, 3, 4]

I further assume that there won't be nested arrays, e.g. [1, [2, 3]] or trailing commas [1,].

Then we just strip the array delimiters

my $line = <STDIN>;
$line =~ s/ ^\s*\[ | \]\s*$ //gx;

and split the array into a Perl array. We can either do this via split

my @array = split /,\s*/, $line;

or via extracting all numbers

my @array = ($line =~ /(\d+)(?:,\s*|$)/g);

The split solution would also allow including strings, e.g [1, two, 3], whereas the second solution is stricter (and therefore perhaps safer).

In a second step, you could parse ranges, e.g. via

@array = map {
   ($_ =~ /^(-?[\d.]+)\s*\.\.\s*(-?[\d.]+)/)
   ? ($1 .. $2)
   : $_
} @array;

If your data structures get more complex (recursing, quoting), I'd highly encourage writing a parser with Regexp::Grammars. This allows you to easily parse recursive structures, and almost anything else.

share|improve this answer
I thought about "regexing" too, but that will be kinda complex to debug if the format gets more complex. I'll definitely take a look at this grammar module! –  Megge Sep 25 '12 at 8:44

Your Answer


