我有一個需求,我從文件接收數組的輸入。根據解析參數來檢查條件
例如,如果數組的內容是2,<,3分別是$ 1,$ 2和$ 3。
我有一個字符串,它是「2 < 3」。我需要檢查條件的有效性,如果真的2 islessthan 3或不。
如何輸入if()條件,如果輸入是我的字符串?
我最近介紹給Perl,並希望探索更多。
我有一個需求,我從文件接收數組的輸入。根據解析參數來檢查條件
例如,如果數組的內容是2,<,3分別是$ 1,$ 2和$ 3。
我有一個字符串,它是「2 < 3」。我需要檢查條件的有效性,如果真的2 islessthan 3或不。
如何輸入if()條件,如果輸入是我的字符串?
我最近介紹給Perl,並希望探索更多。
正如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 ");
感謝您的有用建議。由於我在輸入前已經檢查過運算符,所以我可以安全地使用eval()。謝謝。 – user1999315
如果輸入簡單(數量,運營商數量),您可以通過以下方式解決問題:
#!/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::RecDescent或Marpa::R2。
雖然你可以做一個看起來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相比,用這種方法補充。
(我所要做的就是將它們添加到@ops
在BEGIN{}
)
一種可能性(不一定是一個好一個,它是危險的,在一般情況)是['eval'(HTTP://perldoc.perl。 org/functions/eval.html)運算符。 –