2012-06-01 50 views
20

所以,我碰巧注意到last.fm正在招聘我的领域,并且因为我认识了几个人who workedthere,我虽然在申请。这个Perl单线程究竟是如何工作的?

但我想我最好先看看current staff

那个页面上的每个人都有一条可爱/聪明/笨拙的背带,就像“生命不是千次太短,我们不能忍受自己?”。事实上,这是很有趣的,直到我得到这个:

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' 

这我无法抗拒粘贴到我的终端(那种愚蠢的事情,也许),但它印:

又一个Last.fm黑客,

我认为这将是比较容易弄清楚如何Perl的一个班轮作品。但是我无法真正理解文档,并且我不了解Perl,因此我甚至不确定是否正在阅读相关文档。

所以我尝试修改数字,这让我无处可寻。所以我决定这真的很有趣,值得搞清楚。

这么说,“它是如何工作”是一个有点模糊,我的问题主要是,

那些是什么号码?为什么存在负数和正数,而负数或积极性又重要?

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

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

+0

我现在的:'(* STORE,* TIESCALAR)= map {eval“sub {$ _}”} qw'map {print && sleep $ |} split //,pop bless \ $ | ++'; tie $ T,主; $ T = “又一个Perl爱好者,\ n”' –

回答

28

这是“Just another Perl hacker”,一个Perl米姆的变体。随着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 

pack是一个函数,而printmaplist operators。无论采用哪种方式,函数或非零运算符名称后面紧跟着一个加号,都不能使用+作为二元运算符,因此+开头的符号都是unary operators。这种古怪在manual中有描述。

如果加上括号,使用块语法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))) 

下一个棘手的一点是,q这里是qquote-like operator。它是更常见的写单引号:

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))) 

记住一元加号是无操作(除了强制标量上下文中),这样的事情,现在应该寻找更熟悉。这是对pack函数的调用,用c*的格式,这意味着“任何数量的字符,由他们在当前的字符集数指明”。写这的另一种方法是

print(join("", map {chr($.+=$_)} (74, …, -34))) 

map功能所提供的块适用于参数列表,以便该元件。对于每个元素,$_设置为元素值,并且调用的结果是通过在连续元素上执行块返回的值的列表。写这个程序更长的方式将是

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

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

为了您的下一个任务,请解释此JAPH(由EyesDrop生成)。

''=~('(?{'.('-)@.)@_*([]@[email protected]/)(@)@[email protected]),@(@@[email protected])' 
^'][)@]`}`]()`@[email protected]]@%[`}%[@`@!#@%[').',"})') 

请勿在生产代码中使用任何此类代码。

+1

一切关于这个答案是真棒。很好的解释,你添加了一堆链接,你添加了一个后续 - 希望我能+20这个 –

22

背后的基本思想非常简单。您有一个包含字符的ASCII值的数组。为了使事情变得更复杂一点,你不要使用绝对值,而是使用绝对值,但除第一个之外的其他值。这样的想法是将特定值加到前一个,例如:

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

虽然$.是Perl中的一个特殊变量,但在这种情况下并不意味着什么特别。它只是用于保存上一次的值,并添加当前元素:

map($.+=$_, ARRAY) 

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

Perl中的q函数用于单引号文字字符串。例如。你可以使用像

q/Literal $1 String/ 
q!Another literal String! 
q,Third literal string, 

这意味着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);