How can I convert a scalar to a range list ???

H

hekutu

Dear all:

The follwing small program runs well.
==================
my @b = (1..10);
print @b;
==================
The output is:12345678910

But I want to replace the range list with a
flexible scalar, the new program looks like:
=========================
my $a = "(1..10)";
my @b = $a;
print @b;
=========================
The output is:(1..10)

The scalar is still the scalar. How can I convert
the text scalar "(1..10)" to a range list?

Thank you!
 
A

anno4000

Dear all:

The follwing small program runs well.
==================
my @b = (1..10);
print @b;
==================
The output is:12345678910

But I want to replace the range list with a
flexible scalar, the new program looks like:
=========================
my $a = "(1..10)";

Avoid the variables names $a and $b. They can mess up sort routines.
my @b = $a;
print @b;
=========================
The output is:(1..10)

The scalar is still the scalar. How can I convert
the text scalar "(1..10)" to a range list?

I'm not sure what you mean exactly, but try

my $x = join '', 1 .. 10;

Anno
 
P

Paul Lalli

But I want to replace the range list with a
flexible scalar, the new program looks like:
=========================
my $a = "(1..10)";
my @b = $a;
print @b;
=========================
The output is:(1..10)

The scalar is still the scalar. How can I convert
the text scalar "(1..10)" to a range list?

I'm wary to give this answer, because if you don't understand its
dangers, you can really mess things up. Regardless, it is the actual
answer to your question. The function that converts a plain string to
executable Perl code is C<eval>. Before reading further, or trying it
out, *please* read:
perldoc -f eval

Once you've read that, take a look at this sample solution:
$ perl -le'
my $x = q{(1..10)};
my @y = eval $x;
print "@y";
'
1 2 3 4 5 6 7 8 9 10

Please make sure you understand the dangers involved here. If $x could
be any user-entered string, avoid this method like the plague. Use it
if and ONLY if you are 100% sure you know the possible values this
string can have. (Consider for example, what would happen if the user
did not enter "(1..10)", but instead "system('rm -rf /home/')" )

At the very least, you should be checking the format of the
user-entered string:

if ($x !~ /^\(\d+\.\.\d+\)$/) {
die "'$x' not in correct format!!\n";
}

Paul Lalli
 
P

Paul Lalli

dangers, you can really mess things up. Regardless, it is the actual
answer to your question. The function that converts a plain string to
executable Perl code is C<eval>. Before reading further, or trying it
out, *please* read:
perldoc -f eval

Once you've read that, take a look at this sample solution:
$ perl -le'
my $x = q{(1..10)};
my @y = eval $x;
print "@y";
'
1 2 3 4 5 6 7 8 9 10

Please make sure you understand the dangers involved here. If $x could
be any user-entered string, avoid this method like the plague. Use it
if and ONLY if you are 100% sure you know the possible values this
string can have. (Consider for example, what would happen if the user
did not enter "(1..10)", but instead "system('rm -rf /home/')" )

At the very least, you should be checking the format of the
user-entered string:

if ($x !~ /^\(\d+\.\.\d+\)$/) {
die "'$x' not in correct format!!\n";
}


.... and even as I pushed the Post button, I realized the advice I
should have given. Abandon eval(). Completely. Instead retain that
pattern match above, and use that to get your range:

my @y;
if ($x =~ /^\((\d+)\.\.\(d+)\)$/) {
@y = ($1..$2);
} else {
die "'$x' not in correct format!!\n";
}

Much better.

Paul Lalli
 
M

Mirco Wahab

my $a = "(1..10)";
my @b = $a;
print @b;
=========================
The output is:(1..10)

The scalar is still the scalar. How can I convert
the text scalar "(1..10)" to a range list?

Aside from Anno's notation
of the Perl standard idiom:

{
my $rangestring = join '', 1 .. 10;
}

you could, depending on your
program and your goals, use
any other method that constructs
strings from array/list elements,
like:

{
my $rangestring = '';
$rangestring .= $_ for 1..10;
}


{
local $" = '';
my $rangestring = "@{ [1..10] }";
}


(But use Anno's if possible)

Regards

M.
 
M

Mirco Wahab

Mirco Wahab wrote:

After misinterpreting your intention
and reading Pauls article ...

Could a "closure" be the solution?

my $range = sub { (1..10) };

...
...

my @array = & $range;
# or
# my @array = $range->();

Regards

M.
 
B

Brian McCauley

[ speaking of eval ]
Use it
if and ONLY if you are 100% sure you know the possible values this
string can have. (Consider for example, what would happen if the user
did not enter "(1..10)", but instead "system('rm -rf /home/')" )

This advice always strikes me as flawed.

So long as you know the data is comming from the person as whom the
scipt is running the there's no problem. By "the person as whom the
scipt is running" I mean a person who can, by definition, perform any
action permitted to the current user ID.
 
T

Ted Zlatanov

On 26 Jan 2007, (e-mail address removed) wrote:

[ speaking of eval ]
Use it
if and ONLY if you are 100% sure you know the possible values this
string can have. (Consider for example, what would happen if the user
did not enter "(1..10)", but instead "system('rm -rf /home/')" )

This advice always strikes me as flawed.

So long as you know the data is comming from the person as whom the
scipt is running the there's no problem. By "the person as whom the
scipt is running" I mean a person who can, by definition, perform any
action permitted to the current user ID.

But how do you know this for sure?

What if the person was tricked into typing it in?

What if they used the wrong input file or typed the wrong command?

It's never a good idea to assume your users' input is the same as
their intentions. It's an easy assumption, and certainly it makes
software simpler, but it complicates the users' lives. Software is
supposed to work the other way.

I have the same problem with doing configuration files through "do
file.conf". You just can't expect the system administrator to assume
the burden of securing your application's configuration, because in
principle they should. In practice they won't.

Ted
 
D

Dr.Ruud

(e-mail address removed) schreef:
The follwing small program runs well.
==================
my @b = (1..10);
print @b;
==================
The output is:12345678910

But I want to replace the range list with a
flexible scalar, the new program looks like:
=========================
my $a = "(1..10)";
my @b = $a;
print @b;
=========================
The output is:(1..10)

The scalar is still the scalar. How can I convert
the text scalar "(1..10)" to a range list?

perl -Mstrict -wle'

my $a = q/(1,10)/;
print $a;

if ( my ($min, $max) = $a =~ /[0-9]+/g ) {
print $min; print $max;

my @b = $min .. $max;
print @b;
}
'
 
D

Dr.Ruud

Dr.Ruud schreef:
perl -Mstrict -wle'

my $a = q/(1,10)/;
print $a;

if ( my ($min, $max) = $a =~ /[0-9]+/g ) {
print $min; print $max;

my @b = $min .. $max;
print @b;
}
'

Oops, this doesn't work well for something like

my $a = q/(1,abc)/;

Revision:

$ perl -Mstrict -wle '

my $a = q/(1,10)/;
print qq/input>$a</;

if ( 1 < (my ($min, $max) = $a =~ /[0-9]+/g)) {
print $min;
print $max;

my @b = $min .. $max;
print @b;
print qq/@b/;
}
else {
die qq/input invalid\n/;
}
'
 
H

hekutu

Dear Paul:
Thank you very much! I have read the perldoc of "eval".
The suggestion you give me is the exact solution to my
problem. Since "eval" is so dangerous could you give
me more hints?
I'm writting a perl script which needs the user to input
one or more integers:
[hekutu@localhost]$ ./atom.pl 1 2 3 4 5 6 7 8 9 10
The input may be very long so I try to interprate the
parameters as perl-style list:
[hekutu@localhost]$ ./atom.pl 1..10
So in my question the text scalar, which is the parameter
that user inputs, needs to be cast into list range.
I hope you could understand my question, could you give
me more hints? Thank you!

Regards

hekutu
 
H

hekutu

Hi, Michele
I'm writting a perl script which needs the user to input
one or more integers:
[hekutu@localhost]$ ./atom.pl 1 2 3 4 5 6 7 8 9 10
The input may be very long so I try to use perl-style list
parameters.
[hekutu@localhost]$ ./atom.pl 1..10
In my question the text scalar, which is the parameter
that user inputs "1..10", needs to be cast into list range.
Sorry for disturbing you.

Regards

hekutu

my $a = "(1..10)";
my @b = $a;
print @b;
=========================
The output is:(1..10)
The scalar is still the scalar. How can I convert
the text scalar "(1..10)" to a range list?As others explained you the strict answer to your question would be to
use string eval(). But as others also explained eval() and in
particular string eval() is evil(TM). Thus you can use a workaround
like the one suggested by Paul Lalli: use a regex to validate your
scalar and extract the range extremes, and use them to build the range
itself. OTOH it seems strange to me that you have the exact "(1..10)"
scalar rather than the extremes in the first place, so I smell some
degree of XY problem (see e.g.
<http://perlmonks.org/?node=XY+problem>) here. What are you really
trying to do?

Michele
--
{$_=pack'B8'x25,unpack'A8'x32,$a^=sub{pop^pop}->(map substr
(($a||=join'',map--$|x$_,(unpack'w',unpack'u','G^<R<Y]*YB='
.'KYU;*EVH[.FHF2W+#"\Z*5TI/ER<Z`S(G.DZZ9OX0Z')=~/./g)x2,$_,
256),7,249);s/[^\w,]/ /g;$ \=/^J/?$/:"\r";print,redo}#JAPH,
 
G

Gunnar Hjalmarsson

The follwing small program runs well.
==================
my @b = (1..10);
print @b;
==================
The output is:12345678910

But I want to replace the range list with a
flexible scalar, the new program looks like:
=========================
my $a = "(1..10)";
my @b = $a;

my @b = eval $a;
 
P

Paul Lalli

Thank you very much! I have read the perldoc of "eval".
The suggestion you give me is the exact solution to my
problem. Since "eval" is so dangerous could you give
me more hints?

Did you read the message to which you are replying? My second
message, that said to NOT use eval at all? Just use a pattern match:

my @y;
if ($x =~ /^\((\d+)\.\.\(d+)\)$/) {
@y = ($1..$2);
} else {
die "'$x' not in correct format!!\n";
}


Paul Lalli
 
X

xhoster

Dear Paul:
Thank you very much! I have read the perldoc of "eval".
The suggestion you give me is the exact solution to my
problem. Since "eval" is so dangerous could you give
me more hints?
I'm writting a perl script which needs the user to input
one or more integers:
[hekutu@localhost]$ ./atom.pl 1 2 3 4 5 6 7 8 9 10
The input may be very long so I try to interprate the
parameters as perl-style list:
[hekutu@localhost]$ ./atom.pl 1..10

I do this something like this:

foreach (split /,/,$expression) {
if (/^\d+$/) {
push @group,$_;
next;
};
if ( /^(\d+)[-.]+(\d+)$/) {
push @group, ($1 .. $2 );
next;
};
die "The subexpression $_ in $expression is invalid\n";
};

It lets me specify disjoint ranges, such as 1-20,23,28-50, on the command
line. Also, you can use the perlish ".." or the more intuitive but
nonPerlish "-". (it also lets you use ".", which may cause problems
if things don't need to be integers.)

Xho
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,202
Messages
2,571,057
Members
47,662
Latest member
sxarexu

Latest Threads

Top