这个Perl单行程如何实际工作?

mag*_*tar 21 perl

所以,我碰巧注意到last.fm正在我的地区招聘,因为我认识一些 那里工作的,我申请了.

但我想我最好先看一下目前的工作人员.

那个页面上的每个人都有一个可爱/聪明/愚蠢的背带,比如"生命不是一千倍太短,我们无法忍受自己?".事实上,这是非常有趣的,直到我达到这个:

perl -e'print+pack+q,c*,,map$.+=$_,74,43,-2,1,-84, 65,13,1,5,-12,-3, 13,-82,44,21, 18,1,-70,56, 7,-77,72,-7,2, 8,-6,13,-70,-34'
Run Code Online (Sandbox Code Playgroud)

我无法抗拒粘贴到我的终端(也许是一种愚蠢的事情),但它打印出来:

只是另一个Last.fm黑客,

我认为弄清楚Perl单线程如何工作会相对容易.但我真的无法理解文档,我不知道Perl,所以我甚至不确定我是否正在阅读相关文档.

所以我尝试修改数字,这让我无处可去.所以我认为这真的很有趣,值得一试.

所以,"它是如何工作的"有点模糊,我的问题主要是,

那些数字是多少?为什么有负数和正数,否定性或积极性是否重要?

运营商的组合是+=$_做什么的?

pack+q,c*,,做什么?

Gil*_*il' 29

这是"Just another Perl hacker"的一个变种,一个Perl meme.随着JAPH的到来,这个相对温和.

您需要做的第一件事是弄清楚如何解析perl程序.它缺少函数调用的括号,+并以有趣的方式使用类似于引号的运算符.原来的程序是这样的:

print+pack+q,c*,,map$.+=$_,74,43,-2,1,-84, 65,13,1,5,-12,-3, 13,-82,44,21, 18,1,-70,56, 7,-77,72,-7,2, 8,-6,13,-70,-34
Run Code Online (Sandbox Code Playgroud)

pack是一个函数,而printmap列表操作.无论哪种方式,紧跟一个加号的函数或非空运算符名称都不能+用作二元运算符,因此+开头的两个符号都是一元运算符.手册中描述了这种奇怪之处.

如果我们添加括号,使用块语法map,并添加一些空格,我们得到:

print(+pack(+q,c*,,
            map{$.+=$_} (74,43,-2,1,-84, 65,13,1,5,-12,-3, 13,-82,44,21,
                         18,1,-70,56, 7,-77,72,-7,2, 8,-6,13,-70,-34)))
Run Code Online (Sandbox Code Playgroud)

下一个棘手的问题是q这里是q 类似引用的运算符.它通常用单引号编写:

print(+pack(+'c*',
            map{$.+=$_} (74,43,-2,1,-84, 65,13,1,5,-12,-3, 13,-82,44,21,
                         18,1,-70,56, 7,-77,72,-7,2, 8,-6,13,-70,-34)))
Run Code Online (Sandbox Code Playgroud)

请记住,一元加号是一个无操作(除了强制标量上下文),所以现在应该看起来更熟悉了.这是对pack函数的调用,格式c*为"任意数量的字符,由当前字符集中的数字指定".另一种写这个的方法是

print(join("", map {chr($.+=$_)} (74, …, -34)))
Run Code Online (Sandbox Code Playgroud)

map函数按顺序将提供的块应用于参数列表的元素.对于每个元素,$_将其设置为元素值,并且map调用的结果是通过对连续元素执行块返回的值列表.编写这个程序的更长的方法是

@list_accumulator = ();
for $n in (74, …, -34) {
    $. += $n;
    push @list_accumulator, chr($.)
}
print(join("", @list_accumulator))
Run Code Online (Sandbox Code Playgroud)

$.变量包含运行的总数.选择数字,使得运行总数是作者想要打印的字符的ASCII代码:74 = J,74 + 43 = 117 = u,74 + 43-2 = 115 = s等.它们是负的还是正的,具体取决于是否每个字符都以ASCII顺序在前一个字符之前或之后.

对于您的下一个任务,请解释此JAPH(由EyesDrop生成).

''=~('(?{'.('-)@.)@_*([]@!@/)(@)@-@),@(@@+@)'
^'][)@]`}`]()`@.@]@%[`}%[@`@!#@%[').',"})')
Run Code Online (Sandbox Code Playgroud)

不要在生产代码中使用任何此类代码.

  • 关于这个答案的一切都很棒.很好的解释,你添加了一堆链接,你添加了一个后续 - 希望我能+20这个 (2认同)

Ulr*_*gel 22

这背后的基本思想非常简单.您有一个包含字符的ASCII值的数组.为了使事情变得更复杂,你不要使用绝对值,而是使用相对的值,除了第一个.因此,我们的想法是将特定值添加到前一个值,例如:

  1. 74 - > J
  2. 74 + 43 - > u
  3. 74 + 42 +( - 2) - > s

尽管$.在Perl中是一个特殊的变量,但在这种情况下它并不意味着什么特别的东西.它仅用于保存以前的值并添加当前元素:

map($.+=$_, ARRAY)
Run Code Online (Sandbox Code Playgroud)

基本上它意味着将当前列表元素($_)添加到变量中$..这将返回一个新数组,其中包含新句子的正确ASCII值.

qPerl中的函数用于单引号的文字字符串.例如,你可以使用像

q/Literal $1 String/
q!Another literal String!
q,Third literal string,
Run Code Online (Sandbox Code Playgroud)

这意味着pack+q,c*,,基本上pack 'c*', ARRAY.的c*在改性剂pack解释该值作为字符.例如,它将使用该值并将其解释为字符.

它基本归结为:

#!/usr/bin/perl
use strict;
use warnings;

my $prev_value = 0;

my @relative = (74,43,-2,1,-84, 65,13,1,5,-12,-3, 13,-82,44,21, 18,1,-70,56, 7,-77,72,-7,2, 8,-6,13,-70,-34);
my @absolute = map($prev_value += $_, @relative);

print pack("c*", @absolute);
Run Code Online (Sandbox Code Playgroud)