Как я могу «сохранить» оператор внутри переменной в Perl? - PullRequest
7 голосов
/ 21 марта 2010

Я ищу способ сделать это в Perl:

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

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

Здесь $b "содержит" оператор ... я могу это сделать?Может быть, каким-то другим способом?

Ответы [ 6 ]

18 голосов
/ 21 марта 2010

Приятно видеть, как люди открывают для себя функциональное программирование. : -)

К счастью, Perl имеет возможность создавать и хранить функции на лету. Например, пример в вашем вопросе будет выглядеть так:

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

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

В этом примере ссылка на анонимную подпрограмму хранится в $b, подпрограмма имеет тот же синтаксис для передачи аргумента, что и обычный. -> затем используется для вызова по ссылке (тот же синтаксис, который вы, вероятно, используете для ссылок на массивы и хэши).

Но, конечно, если вы хотите просто построить выражения Perl из произвольных строк, вы можете использовать eval:

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

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

Однако делать это с помощью eval небезопасно, если строка, которую вы проверяете, содержит части, которые вводятся пользователем. Синан Юнюр прекрасно объяснил это в своем ответе-комментарии .

8 голосов
/ 21 марта 2010

Это должен быть комментарий, но комментарии слишком тесны для чего-то подобного, поэтому я делаю это CW.

Для случая, который вы показали, где содержимое переменных, которые будут переданы в string eval , принятое решение является правильным.

Если, однако, содержимое $a и $b взято из пользовательского ввода, взгляните на следующий скрипт:

#!/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";
}

Если пользователь вводит строки, ничто не мешает пользователю передать вашей программе строку ';system "rm -rf /bin"'.

Итак, правильное решение вашего вопроса потребует написания или использования синтаксического анализатора выражений.

Кстати, вы не должны использовать $a и $b в качестве имен переменных, поскольку они являются локальными переменными магического пакета, используемыми sort , и поэтому они освобождаются от строгого & mdash ; и вы должны всегда использовать строгие и предупреждения в своих программах.

8 голосов
/ 21 марта 2010

Как насчет определения функции, которая включает необходимое условие:

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

if ( $cond->( $a ) ) { 
     ...
}
6 голосов
/ 21 марта 2010
$a = "60"; $b = "< 80";
if( eval($a. $b)){
  print "ok";
}

см. perldoc eval , чтобы узнать больше

1 голос
/ 21 марта 2010

Интересно, интересует ли Number :: Compare здесь?Из примера:

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

 my $c = Number::Compare->new(">1M");
 $c->(1_200_000);                          # slightly terser invocation
0 голосов
/ 02 февраля 2018

Более безопасная форма, если вы доверяете (или можете достаточно проверить) $ op и не доверяете безопасности входных данных:

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") )
{
 ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...