2012-06-01 49 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);