简体   繁体   中英

How can I “store” an operator inside a variable in Perl?

I'm looking for a way to do this in Perl:

$a = "60"; $b = "< 80";

if ( $a $b ) {  then .... }

Here, $b "holds" an operator... can I do this? Maybe some other way?

It's nice to see how people discover functional programming. :-)

Luckily, Perl has capabilities to create and store functions on-the-fly. For example, the sample in your question will look like this:

$a = "60"; $b = sub { $_[0] < 80 };

if ( $b->($a) ) { .... }

In this example, a reference to the anonymous subroutine is stored in $b , the sub having the same syntax for argument passing as a usual one. -> is then used to call-by-reference (the same syntax you probably use for references to arrays and hashes).

But, of course, if you want just to construct Perl expressions from arbitrary strings, you might want to use eval :

$a = "60"; $b = " < 80";

if ( eval ("$a $b") ) { .... }

However, doing this via eval is not safe, if the string you're eval-ing contains parts that come as user input. Sinan Ünür explained it perfectly in his answer-comment .

How about defining a function that wraps the needed condition:

my $cond = sub { $_[0] < 80 };

if ( $cond->( $a ) ) { 
     ...
}

This should be a comment but comments are too cramped for something like this so I am making it CW.

For the case which you showed where the contents of the variables that are going to be passed to string eval , the accepted solution is correct.

If, however, the contents of $a and $b come from user input, then take a look at the following script:

#!/usr/bin/perl

use strict; use warnings;

my $x = '80';
my $y = '; warn "evil laugh!\n"; exit';

if ( eval ($x . $y) ) {
    print "it worked!!!\n";
}

If the strings are entered by the user, there is nothing preventing the user from passing to your program the string ';system "rm -rf /bin"' .

So, the correct solution to your question would require writing or using an expression parser.

BTW, you should not use $a and $b as variable names as the are magical package local variables used by sort and as such they are exempt from strict — and you must always use strict and warnings in your programs.

$a = "60"; $b = "< 80";
if( eval($a. $b)){
  print "ok";
}

see perldoc eval for more

I wonder if Number::Compare is of any interest here. From the example:

 Number::Compare->new(">1Ki")->test(1025); # is 1025 > 1024

 my $c = Number::Compare->new(">1M");
 $c->(1_200_000);                          # slightly terser invocation

Safer form if you trust (or can sufficiently validate) $op and don't trust the safety of the inputs:

my $compare_x = $user_input_x;
my $compare_y = $user_input_y;
my $op = <some safe non-user-input, or otherwise checked against a safe list>;
if ( eval("\$compare_x $op \$compare_y") )
{
 ...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM