我对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)
时没有区别。我认为它应该输出四行。
我有什么错误吗?
答案 0 :(得分:8)
文件的内容实际上并不重要。然而,重要的是行号(每个处理行的行号),因为这是针对..
运算符的每个操作数进行检查的内容。它实际上可以写成......
print if ($. == 1) .. ($. == 5);
根据触发规则,print
将在行号等于1时开始工作,并在行号等于5时结束。..
和{{之间的唯一区别触发器中的1}}是关于在同一表达式上测试两个操作数,这在这种情况下是无关紧要的。
您可能想要使用的是......
...
...也就是说,在一个范围内测试该行的内容。但是在列表上下文中print if $_ ~~ [1..5];
和..
之间没有区别 - 它们都返回相同的范围:
...
现在有些事情......好吧,没那么完全不同。 )考虑following:
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
运营商更放松。对于第一行,由于第一个条件是真实的,网关是打开的 - 但是这里没有检查第二个表达式!但是,对于第二行,关闭网关将进行检查 - 但...
设法通过。
答案 1 :(得分:5)
在你的情况下无关紧要,因为..
无法对同一行号进行触发。
引用perlop:
在标量上下文中,“
..
”返回a 布尔值。运营商是 双稳态,如触发器,和 模拟行范围(逗号) 运营商 sed , awk ,各种各样 编辑。每个“..
”运算符都维护 它自己的布尔状态,甚至跨越 调用包含的子例程 它。只要它的左边就是假的 操作数是假的。一旦离开 操作数是真的,范围运算符 在右操作数为止之前保持为真 是的,AFTER是范围操作员 再次变得虚假。它不会成为 假到下一次的范围 运算符被评估。它可以测试 正确的操作数,并成为虚假的 同样的评价它成为现实(如 awk ),但它仍然返回true一次。 如果你不想让它测试正确的话 操作数直到下一次评估为止 在 sed 中,只需使用三个点(“...
”) 而不是两个。在所有其他方面, “...
”的行为就像“..
”一样。不评估右操作数 而操作员处于“假”状态 状态,左操作数不是 在运营商所在的时候进行评估 “真实”的状态。优先权是 低于
||
和&&
。价值 返回的是空字符串 表示错误或序列号 (从1开始)为真。该 序列号为每个重置 遇到的范围。最后的序列 范围内的数字包含字符串“E0” 附加到它,这不会影响 它的数值,但给你 如果你想要搜索的东西 排除端点。你可以排除 通过等待的开始点 序号大于1.如果标量“
..
”的任一操作数是a 常量表达式,该操作数是 如果相等则认为是真的(==
) 到当前的输入行号($.
变量)。
答案 2 :(得分: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 - Bar”时,/0/
被满足,因此状态变为 true 。同时,/1/
也得到满足,因此下一个状态突然变为 false ,这是..
不同的地方来自...
,因为...
现在不会评估/1/
,而下一个状态仍然是 true 。所以“1 - Baz”将不会打印出来。否则,当使用...
时,可以打印出该行。
答案 3 :(得分:0)
在Perl中,如果它返回undef
,空字符串或0值,则 false 。否则,它被视为true
。
你说的是:
print if (1..5);
这意味着如果$_
返回真值,则会打印(1..5)
的内容。好吧,(1..5)
返回一个包含五个成员的数组。这意味着if (1..5)
始终为true,文件中的每一行都会打印出来。