Perl对grep {//}和eval {grep //}语法的混淆

时间:2014-10-15 10:37:59

标签: perl

请详细了解 grep < strong>< strong>> Perl 这两种方式之间的差异

eval {grep /pattern/, ....};

和正常的,

grep {/pattern/} ....

1 个答案:

答案 0 :(得分:3)

首先,您的替代品之间存在2个独立差异,并且它们具有不同的用途。在grep中包装eval可以捕获通常致命的错误(如正则表达式中的语法错误)。在grep关键字后面放置一个块,可以使用比单个表达式更复杂的匹配规则。

以下是您可以从2个示例中进行的4种组合:

@y = grep /pattern/, @x;             # grep EXPR, no eval
@y = grep { /pattern/ } @x;          # grep BLOCK, no eval
eval { @y = grep /pattern/, @x };    # grep EXPR inside eval BLOCK
eval { @y = grep { /pattern/ } @x }; # grep BLOCK inside eval BLOCK

现在我们可以通过两个不同的问题详细了解:您从eval获得了什么,以及使用grep BLOCK语法获得了什么?在上面显示的简单情况中,你不会从任何一个中获得任何东西。

当您想要进行匹配条件比简单正则表达式更复杂的grep时,grep BLOCK可让您更灵活地表达条件。您可以在块中放置多个语句并使用临时变量。例如grep中的这个grep:

# Note: not the most efficient method for finding an intersection of arrays.
my @a = qw/A E I O U/;
my @b = qw/A B D O P Q R/;
my @intersection = grep { my $x = $_; grep { $_ eq $x } @b } @a;
print "@intersection\n";

在上面的示例中,我们需要一个临时的$x来保存外部grep正在测试的值,以便可以将其与内部$_中的grep进行比较。内部grep可以在没有BLOCK的情况下编写为grep $_ eq $x, @b,但我认为对两者使用相同的语法看起来更好。

如果您正在查找在运行时确定的正则表达式的匹配项,并且在正则表达式无效时您不希望程序中止,那么eval块将非常有用。例如:

@x = qw/foo bar baz quux xyzzy/;
do {
  print STDERR 'Enter pattern: ';
  $pat = <STDIN>;
  chomp $pat;
  eval {
    @y = grep /$pat/, @x;
  };
} while($@);
print "result: @y\n";

我们要求用户提供模式并打印@x的匹配列表。如果模式不是有效的正则表达式,eval会捕获错误并将其放入$@,程序将继续运行(&#34;无效&#34;消息将被打印并且循环继续所以用户可以再试一次。)当输入有效的正则表达式时,没有错误,因此$@为假,结果为&#34;线打印。样品运行:

Enter pattern: z$
result: baz
Enter pattern: ^(?!....)
result: foo bar baz
Enter pattern: ([^z])\1
result: foo quux
Enter pattern: [xyz
Invalid pattern
Enter pattern: [xyz]
result: baz quux xyzzy
Enter pattern: ^C

请注意eval在固定的regexp中没有捕获语法错误。这些是在编译脚本时编译的,所以如果你有一个像

这样的简单脚本
perl -ne 'print if eval { /[xyz/ } or eval { /^ba/ }'

立即失败。 eval没有帮助。与

比较
perl -ne '$x = "[xyz"; $y = "^ba"; print if eval { /$x/ } or eval { /$y/ }'

这是同样的事情,但是使用从变量构建的正则表达式 - 这个运行并打印/^ba/的匹配项。第一个eval始终返回false(并设置$@,如果您不看它,这并不重要。