根据解析args来检查条件

时间:2013-01-22 06:44:42

标签: perl

我需要从文件到数组接收输入。

例如,如果数组的内容为2,则<,3分别为$ 1,$ 2和$ 3。

我有一个“2< 3”的字符串。我需要检查条件的有效性,如果真的是2小于3或不是。

如果输入是我的字符串,如何发送if()条件的输入?

最近被介绍给Perl并希望了解更多。

3 个答案:

答案 0 :(得分:3)

如果您的输入很简单(数字,运算符,数字),您可以通过以下方式解决:

#!/usr/bin/perl
use warnings;
use strict;

my $input = shift;
my ($num1, $op, $num2) = $input =~ /([0-9]+) *([<=>]) *([0-9]+)/;
if ('=' eq $op and $num1 == $num2
    or
    '<' eq $op and $num1 < $num2
    or
    '>' eq $op and $num1 > $num2) {
    print "Yes\n";
} else {
    print "No\n";
}

或更短,使用“太空飞船”操作员<=>

#!/usr/bin/perl
use warnings;
use strict;

my @operations = qw(= > <);

my $input = shift;
my ($num1, $op, $num2) = $input =~ /([0-9]+) *([<=>]) *([0-9]+)/;
if ($op eq $operations[$num1 <=> $num2]) {
    print "Yes\n";
} else {
    print "No\n";
}

如果表达式是递归的(即(2+3)>(4+7)),则应该学习解析。我建议Parse::RecDescentMarpa::R2

答案 1 :(得分:2)

正如Jonathan Leffler所说,这很危险。你永远不应该运行这样的代码。这很危险。

最简单(也是最危险)的方式当然是eval。请参阅Jonathan在评论中链接的文档。

更安全的选择是使用Safe。它创建了一个隔离区,可以将语法的使用限制为您可以预先定义的Perl的特定部分。这是人们用来例如制作可以运行Perl代码的IRC机器人或网站。一个很好的例子是freenode上的#perl中的perlbot。

免责声明:请仔细阅读DOC !不要只是复制这些东西。阅读有关opcodes的说明!

这是一些示例代码。

use strict; use warnings;
use Safe;
$compartment = new Safe;
$compartment->permit(qw(:base_core));
$result = $compartment->reval(" 2 < 3 ? 1 : 0 ");

答案 2 :(得分:0)

虽然你可以做一个花哨的if声明,但它们往往会非常冗长,并且容易出错。

if ('=' eq $op and $num1 == $num2
  or
    '<' eq $op and $num1 < $num2
  or
    '>' eq $op and $num1 > $num2) {
  print "Yes\n";
} else {
  print "No\n";
}

或者(如果您小心),您可以使用eval()

# check $input here
...
$input =~ s/[^=]=[^=]/==/;
if( eval $input ){ ...

虽然每次输入时都必须编译每个输入 以这种方式安全使用也很困难。


相反,我想向您展示一些高级的Perl hackery。

虽然它确实使用eval(),但它确实安全,因为我完全控制了它编译的内容。

#!/usr/bin/perl
use warnings;
use strict;

our %compare;
our $compare_match;
BEGIN{
  # list of simple ops
  my @ops = qw'< <= == != > >= lt le eq gt ge ne';
  for my $op (@ops){
    $compare{$op} = eval"sub{ \$_[0] $op \$_[1]}";
  }

  push @ops, '='; # for $compare_match
  $compare{'='} = $compare{'=='}; # copy sub

  # longest first
  @ops = sort { length($b) <=> length($a) } @ops;
  local $" #"
    = '|';
  $compare_match = eval"qr{(?:@ops)}";
}

sub check{
  my( $num1, $op, $num2 ) = @_;
  if( @_ == 1 ){
    ($num1,$op,$num2) = 
      $_[0] =~ /([0-9]+) \s* ($compare_match) \s* ([0-9]+)/x;
  } elsif( @_ != 3 ){
    die 'wrong number of arguments'; # could be improved
  }
  unless( $op and exists $compare{$op} ){
    die "unknown op of '$op'"; # could be improved
  }

  # the heart of this implementation
  return $compare{$op}->($num1,$num2);
}
if( check('2<3') ){ # one arg
  print "Yes\n"; # <---
}else{
  print "No\n";
}
if( check('2>3') ){ # one arg
  print "Yes\n";
}else{
  print "No\n"; # <---
}

if( check(qw'2 < 3') ){ # three arg
  print "Yes\n"; # <---
}else{
  print "No\n";
}
if( check(qw'2 > 3') ){ # three arg
  print "Yes\n";
}else{
  print "No\n"; # <---
}

# dies
if( check(qw'2 **** 3') ){ ... }

您应该注意使用此方法添加更多比较操作是多么容易 (我所要做的就是将它们添加到BEGIN{}

中的@ops