关于Perl范围运营商

时间:2013-05-31 07:27:10

标签: perl

我对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)时没有区别。我认为它应该输出四行。 我有什么错误吗?

4 个答案:

答案 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也评估为$. >= 11)。当触发器关闭时,所有下一行必须再次通过第一个条件,这是不可能的。

  • 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,文件中的每一行都会打印出来。