2013-01-22 18 views
0

我有一個需求,我從文件接收數組的輸入。根據解析參數來檢查條件

例如,如果數組的內容是2,<,3分別是$ 1,$ 2和$ 3。

我有一個字符串,它是「2 < 3」。我需要檢查條件的有效性,如果真的2 islessthan 3或不。

如何輸入if()條件,如果輸入是我的字符串?

我最近介紹給Perl,並希望探索更多。

+1

一種可能性(不一定是一個好一個,它是危險的,在一般情況)是['eval'(HTTP://perldoc.perl。 org/functions/eval.html)運算符。 –

回答

2

正如Jonathan Leffler所說,這是危險的。你永遠不應該運行這樣的代碼。這非常危險。

最簡單(也是最危險)的方法當然是eval。請參閱喬納森在評論中提到的文檔。

更安全的選擇是使用Safe。它創建了一個區間,將語法的使用限制在您可以預先定義的Perl特定部分。這是人們用於例如製作可運行Perl代碼的IRC機器人或網站。一個很好的例子就是freenode上的#perl中的perlbot。

免責聲明:請仔細閱讀文檔!不要只是複製這些東西。閱讀關於opcodes的解釋!

下面是一些示例代碼。

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

感謝您的有用建議。由於我在輸入前已經檢查過運算符,所以我可以安全地使用eval()。謝謝。 – user1999315

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

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')){ ... } 

你應該注意到它是多麼容易在更OPS相比,用這種方法補充。
(我所要做的就是將它們添加到@opsBEGIN{}

相關問題