了解这个perl解决方案

时间:2014-11-07 01:30:21

标签: regex perl syntax

我正在尝试解决代码高尔夫练习,其中包括输入测试用例的数量,然后在每个测试用例的每一行中输入一个整数。

为了获得最短的解决方案,我遇到了this解决方案:

#!perl -lp
use bigint;$_=???<>+1:bnok{2*$_}$_ 

我是非常新的perl,因此我没有得到这段代码实际上是如何工作的。如果有人帮我解决这个问题,我将不胜感激。

PS:Asked and closed at codegolf.stackexhange

1 个答案:

答案 0 :(得分:7)

有一些工具可以找出Perl高尔夫球。一个是perlsecret,它记录了许多Perl高尔夫球手使用的“秘密操作员”和技巧。

对于这个特定的代码,了解-p does是什么也很重要。它将代码包装在一堆其他代码中,然后可以将其用于高尔夫目的。

最后,解开Perl高尔夫球的终极工具是B::Deparse。这转换了Perl如何将代码理解为具有缩进等的人类可读Perl。 -p选项使B :: Deparse添加括号,即使它们不是必需的,这有助于阐明优先级。 -d选项可以更准确地表示对象。什么对象?观察。

$ perl -MO=Deparse,-p,-d
#!perl -lp
use bigint;$_=???<>+1:bnok{2*$_}$_

Use of ?PATTERN? without explicit operator is deprecated at - line 2.
BEGIN { $/ = "\n"; $\ = "\n"; }
use bigint;
LINE: while (defined(($_ = <ARGV>))) {
    chomp($_);
    BEGIN {
        $^H{'bigint'} = '1';
        $^H{'binary'} = 'CODE(0x7fc88ba3d580)';
        $^H{'float'} = 'CODE(0x7fc88ba3d478)';
        $^H{'integer'} = 'CODE(0x7fc88b298428)';
    }
    ($_ = (?? ? (<ARGV> + bless( {"sign" => "+","value" => [1]}, 'Math::BigInt' )) : (bnok {
        (bless( {"sign" => "+","value" => [2]}, 'Math::BigInt' ) * $_)
    } $_)));
}
continue {
    (print($_) or die("-p destination: $!\n"));
}
- syntax OK

这揭示了一些更深奥的东西......

  • ???是?PATTERN?运算符加?:三元运算符。具体而言,??是三元的条件。
  • ??的工作方式与//类似,但只会匹配一次,直到reset被调用。因为在此程序中永远不会调用reset,所以它只对该程序匹配一次。 //将匹配任何内容。
  • use bigint将所有整数转换为Math :: BigInt对象。
  • bnok是来自Math::BigInt的二项式系数方法。
  • bnok被用作对整数的间接方法调用(实际上是Math :: BigInt对象)。间接方法调用的格式为method $object @args,因此bnok{2*$_}$_实际为(2*$_)->bnok($_),即central binomial coefficient

使用一些缩进和垂直空白可以更容易理解程序的内容。你需要一个具有良好匹配的编辑器来完成它们。

(
    $_ =
      (?? ? (<ARGV> + bless( {"sign" => "+","value" => [1]}, 'Math::BigInt' ))
          : (bnok {(bless( {"sign" => "+","value" => [2]}, 'Math::BigInt' ) * $_) } $_)
      )
);
  • 因为??只对整个程序匹配一次,所以它用于跳过第一行,即测试次数。
  • 在第一行之后,??将为false,这将触发bnok计算。

有一个细节我还没有解决。为什么<>+1而不是<>?它似乎压制了一个空白行,但我不知道为什么。