我对 Perl 中的范围运算符有疑问。代码在这里:
#! /usr/bin/perl
open FILE, "<test.txt";
while (<FILE>) {
print if (1 .. 5);
}
close FILE;
test.txt 中的内容类似于:
1
2
3
4
5
代码的结果是文件的所有五行。当我使用print if (1 ... 5)
. 我认为它应该输出四行。有什么我做错了吗?
我对 Perl 中的范围运算符有疑问。代码在这里:
#! /usr/bin/perl
open FILE, "<test.txt";
while (<FILE>) {
print if (1 .. 5);
}
close FILE;
test.txt 中的内容类似于:
1
2
3
4
5
代码的结果是文件的所有五行。当我使用print if (1 ... 5)
. 我认为它应该输出四行。有什么我做错了吗?
文件的内容在这里实际上并不重要。然而,重要的是(每个已处理行的)行号,因为这是针对运算符的每个操作数进行检查的..
。其实可以写成...
print if ($. == 1) .. ($. == 5);
根据触发器的规则,当print
行号等于 1 时开始工作,当行号等于 5 时结束。在这种情况下不相关。..
...
您可能想要使用的是...
print if $_ ~~ [1..5];
...也就是说,根据范围测试该行的内容。但是在列表上下文中..
和之间没有区别——它们都返回相同的范围:...
print for (1..5); # 12345
print for (1...5); # 12345 as well
现在有一些东西......好吧,没有那么完全不同。) 考虑以下事项:
while (<DATA>) {
print '..', $_ if 1..($. >= 1);
print '...', $_ if 1...($. >= 1);
}
__DATA__
1
2
3
它打印...
..1
...1
...2
...然后什么都没有,因为...
操作员在同一条第一行..
检查这两个条件。检查第一个条件 ( $. == 1
) 将其打开(并使整个..
表达式的结果等于1
)。但猜猜怎么了?然后它立即关闭,$. >= 1
也评估为1
( true
)。当触发器关闭时,所有下一行都必须再次通过第一个条件,而这不可能发生。
...
操作员更轻松。对于第一行,由于第一个条件为真,因此打开了网关 - 但这里没有检查第二个表达式!但是,将检查第二条线路,关闭网关 - 但2
设法通过。
..
在你的情况下,不能为相同的行号做触发器并不重要。
引用perlop:
在标量上下文中,“
..
”返回一个布尔值。该运算符是双稳态的,就像一个触发器,并模拟sed、awk和各种编辑器的行范围(逗号)运算符。每个 "..
" 运算符都维护自己的布尔状态,即使在调用包含它的子例程时也是如此。只要它的左操作数是假的,它就是假的。一旦左操作数为真,范围运算符保持真,直到右操作数为真,之后范围运算符再次变为假。直到下一次评估范围运算符时它才会变为假。它可以测试正确的操作数并在它变为真的相同评估中变为假(如在 awk),但它仍然返回一次。如果您不希望它在下一次评估之前测试正确的操作数,如sed,只需使用三个点(“...
”)而不是两个点。在所有其他方面,“...
”的行为就像“..
”一样。当运算符处于“假”状态时不计算右操作数,而当运算符处于“真”状态时不计算左操作数。优先级略低于
||
和&&
。返回的值要么是空字符串(表示 false),要么是序列号(以 1 开头)表示 true。对于遇到的每个范围,都会重置序列号。范围中的最终序列号附加了字符串“E0”,这不会影响其数值,但如果您想排除端点,则可以搜索一些内容。您可以通过等待序列号大于 1 来排除起点。如果标量 "
..
" 的任一操作数是常量表达式,则如果该操作数等于 (==
) 与当前输入行号($.
变量),则认为该操作数为真。
谢谢你的回答,启发了我。在阅读了 perldoc 并做了一些测试之后,我想在这里分享我的理解。如果有什么问题,请告诉我。:)
print if (1 .. 5)
是print if ($. == 1 .. $. == 5)
. 表达式的初始状态为false,在读取第一行后,$. == 1
满足并且状态变为true。所以打印第一行。然后是第二行,第三行,第四行。
到了第五行,状态依旧true
。这是决定是否进入阻塞的状态。所以第五行也打印出来了,然后$. == 5
就满足了,这个时候下一个状态就变成了false。因此,如果之后有任何行,它们将不会被打印出来。
..
和这里没有区别...
,因为区别只发生在左操作数返回true时。让我展示一下:
这里的例子是从perlop中选择。这个例子起初让我感到困惑,但让我展示一下我的理解。
@lines = (" - Foo",
"01 - Bar",
"1 - Baz",
" - Quux");
foreach (@lines) {
if (/0/ .. /1/) {
print "$_\n";
}
}
当谈到“01 - 酒吧”时,/0/
满足,因此状态变为真实。并且同时,/1/
也满足了,所以下一个状态突然变成了假,这就是..
不同的地方...
,因为现在...
不求值/1/
,下一个状态还是真。所以“1 - Baz”不会被打印出来。否则,...
使用时,可以打印出这一行。
在 Perl 中,如果它返回一个、一个空字符串或一个 0 值,那么它就是假的。undef
否则,视为true
。
你在说:
print if (1..5);
这意味着如果返回真值,$_
将打印出的内容。(1..5)
好吧,(1..5)
返回一个由五个成员组成的数组。这意味着if (1..5)
总是正确的,并且文件中的每一行都会打印出来。