双色球基本走势图表图双色球基本走势图表图

獻給linux下的perl黑客們-JAPH



作者:    文章來源:
發布日期:2007年03月06日
獻給linux下的perl黑客們-JAPH
提交人: 爬爬蟲 所屬分類: 系統應用 提交日期:2005-04-21 10:24:57  轉載自: //www.linuxkit.com/articleedit.php?newsid=291  
已被瀏覽 192 次 現有回復 0 個


Perl 文化的支柱 JAPH 就是一小段輸出“Just another Perl hacker”的腳本。盡管 Teodor Zlatanov 的這篇文章是為 Perl 的初級或中級程序員撰寫的,本文分析的幾個 JAPH 風格的簡單示例卻能讓即使經驗最豐富的 Perl 愛好者也感到驚訝,并吸引他們參與。本文的作者 Teodor Zlatanov 是一位Perl 專家,他從 1992年起就開始在社區中工作了,除了其他一些工作,他專門研究有關文本解析的開放源代碼工作。
本質上,JAPH 用四行或不到四行的代碼(每行 80 個或者更少的字符)來輸出字符串“Just another Perl hacker”,這樣一來 JAPH 就可以放在一個 USENET 簽名中。USENET 簽名遠遠早于 Perl,這就使 JAPH 成了一個由長期存在的傳統和 Perl 的魔力結合在一起的奇異的混合體。

JAPH:“Just another Perl hacker”
據我們所知,JAPH 格式是在二十世紀九十年代由 Randal Schwartz 推廣的(好幾處信息來源都同意這個說法)。今天,JAPH 到處可見,它們是由該流派的那些不知疲倦的藝術家們制作的,比如 comp.lang.lang.perl.misc 新聞組的 Abigail。

下面的討論中我們將分析 CPAN (請參閱 參考資料)上的規范列表中的一些 JAPH,它們適合初級到中級 Perl 程序員。我在這里會對各種技巧作簡單的說明,但是有興趣的讀者還是應該參閱 Programming Perl,第三版(請參閱 參考資料)來進一步學習。

為了精確地支持這里所給的示例,您的系統中必須安裝有 Perl 5.6.0。最好您還安裝了最新的(2000 或者更新版本)主流 UNIX 系統(Linux、Solaris、BSD)。盡管這些示例也許能在老一點的 Perl 和 UNIX 版本甚至是其它操作系統上運行,您還是應該考慮一下如果它們運行失敗這樣需要解決的問題。每個 JAPH 都以規范列表的格式顯示,帶有一個日期和作者屬性。

優良的
在開始討論更豐富的內容之前,我們先來看看 Randal Schwartz 在 JAPH 的早些時期編寫的四段簡單有趣的代碼。我們下面的第一個示例證明了并不是所有的 JAPH 都是要晦澀難懂的,有一些甚至是很容易看懂的。

清單 1. 一個簡單的 true 條件句
Date: 18 Jun 90 15:53:11 GMT
From: [email protected] (Randal Schwartz)
print "Just another Perl hacker," if "you can´t think of anything better..."


在清單 1 中,既然字符串不為空, if() 語句的值就始終為 true(只有空字符串“”、字符串“0”,數字 0 或其等價的表達形式,或者不定義時其值才為 false)。因而,將一直執行打印語句。

清單 2. 使用 Printf
Date: 15 Jun 90 22:06:24 GMT
From: [email protected] (Randal Schwartz)
printf "%s %s %s %s%c", ´Just´, ´another´, ´Perl´, ´hacker´, 44



清單 2 是另一個早期的樣本,它使用 printf() 的函數來產生所需的輸出,這也證明了如果您愿意的話,Perl 看起來也可以象 C 語言一樣。

在清單 3 中 Schwartz 開始玩花招了。現在我們給 print() 一個重新排列過的數組,然后將這個數組打印出來,單詞之間有空格($ 是一個變量,它告訴 Perl 在一次打印所有數組元素時在元素之間應該放什么東西)。

清單 3. 重新排列數組
Date: 5 Jun 90 19:07:58 GMT
From: [email protected] (Randal Schwartz)
$,=" "; print +("hacker,","Just","Perl","another")[1,3,2,0];



數組前面的 + 使 print() 把緊隨其后的東西當做一個單獨的參數(在本例中因為有圓括號,所以是數組),而不是把圓括號當做是函數調用?;瘓浠八?,我們避免了以下情況: print (´a´, ´b´)[1]; 其中, print() 把‘a’和‘b’當做它的第一個和第二個要打印的參數,然后 Perl 就不知道 [1] 是用來做什么的了。

清單 4 是最早的有記錄可查的 JAPH,還有點別出心裁,使用了 split() 、 sort() 和 grep() :

清單 4. Sort 然后 grep
Date: 6 Feb 90 22:31:17 GMT
From: [email protected] (Randal Schwartz)
print grep(s/^d+(.*)/$1 /, sort(split(/ /,"8hacker, 4Perl 1Just 2another")));



首先,我們把起始字符串分割成四個元素: “8hacker,” “4Perl” “1Just” “2another” 。
然后我們排序 ?D 缺省情況下是按字母數字順序 ?D 得到: “1Just” “2another” “4Perl” “8hacker,” 。

注意 “10Just” 也應該排在 "8hacker" 的前面 ?D 這不是數字排序。

排序后的列表被傳遞到 grep() ,它將每個元素開頭的所有數字都去掉,并在剩下的部分后面加上一個空格。結果是: “Just ” “another ” “Perl ” “hacker, ” 。

最后,在這個列表上調用 print() ,逐字逐元素打印。

糟糕的
看夠了 JAPH 的優點后,現在讓我們來看看它真正“糟糕到極點”的地方。良好的 JAPH 還有循序漸進的教學作用,糟糕的 JAPH 卻讓您的思維混亂得象椒鹽卷餅一樣。當您盯著一段 JAPH 冥思苦想十分鐘卻只能頭疼時,您就知道這個 JAPH 是糟糕的了。

清單 5. 代替和計算
Date: 26 Mar 90 16:20:37 GMT
From: [email protected] (Raymond Chen)
$_=´x"Not ";"x"another ";´x"perl ";x"hacker,"´"´;s/x/print/g;eval eval eval;



這里舉例說明的一個普通的技巧是用另外的單詞來代替原有的一個單詞,然后再計算輸出(實際上,在您進行這個步驟時正在建立 Perl 代碼)。上面的示例中,每一個 "x" 都被換成了 "print" 。您還應該懂得 Perl 中的引用規則。Perl 在那個字符串中計算之后看到的是: x"Not ";"x"another ";´x"perl ";x"hacker,"´" (在 s/// 命令前面加上一個 print() 來察看這一點。)

字符串以一個單引號開頭,所以它也必須以一個單引號結束。如果您往前面找單引號,就會發現有兩個單引號轉義了(帶一個反斜杠),第三個才是真的。

現在,運行替換(在 s/// 命令后面加上一個 print() 自己去看結果): print"Not ";"print"another ";´print"perl ";print"hacker,"´"

接下來是我們的命令了。為什么在這里要運行三個 eval() 命令,而不是僅僅一個呢?仔細看一下。第二個 print() 是在字符串里面的,并不會被第一個 eval() 計算。但第一個 eval() 會返回計算過的第一級字符串: print"another ";´print"perl ";print"hacker,"´ 。它將打印出“Not”。為什么第一個 eval() 不返回字符串的第一部分?因為 eval() 只返回計算過的最后的東西。用“print eval”代替“eval eval eval”作為最后的語句,看看這樣操作的效果如何。

第二個 eval 是做什么的呢?它是用來計算第二個,而不是第三個或第四個 print() 語句的。如果您觀察一下就會發現它們兩個都是在一對單引號內的字符串里的。第二個 eval 會返回含有第三個和第四個 print() 語句的字符串,留下剛剛打印了“another ”的那個語句。所以第二個 eval 將返回: print"perl ";print"hacker,"

第三個 eval 會運行那兩個 print() 語句來結束這段 JAPH(奇怪的是,它會打印出“Not another perl hacker,”)。

正如您所看到的,分解一段糟糕的 JAPH 是要花一點時間的。即使是象我們剛才解譯的那么簡單的東西,最后都有好幾個復雜的層次。

讓我們來分析另一個糟糕到極點的 JAPH :

清單 6. Abigail 的天書
#Abigail
$_ = "x3Cx3Cx45x4Fx54"; s/<<EOT/<<EOT/e; print;
Just another Perl Hacker
EOT



清單 6 看起來也象是一段簡單的 JAPH。為什么?字符串就在那里 ?D 有什么神秘的地方?其實,Abigail 風格就是以一種新的方式來使用您以前所見過的東西。例如,在這里,給操作符 s/// 加上了修飾符“e”。這樣就讓它在進行替換之前計算右邊的表達式。這樣一來,“<<EOT”就被自己替換成下一行到 EOT 行之間的所有字符 ?D 在這個示例中為“Just another Perl Hacker”。

編碼的 $_字符串最后包含“<<EOT”,所以操作符 s/// 進行的替換最后會將 字符串 “<<EOT”替換成計算“<<EOT”的結果,即字符串“Just another Perl Hacker”。 print() 語句負責打印該字符串。

編碼過的字符串和看似簡單的替換是 JAPH 的支柱。尤其是替換,它可以用新的令人驚奇的方式進行,您會發現在您自己的代碼中這些方式很有用。

下面是 Abigail 的另一段如惡魔般讓您絞盡腦汁的 JAPH:

清單 7. Abigail 解釋的原型
#Abigail
perl -wle ´sub _ "Just another Perl Hacker"; print prototype &_´



理解這段 JAPH 需要一定的使用原型的知識。請參閱“perldoc -f sub”和“perldoc -f prototype”文檔來了解這是怎么一回事?;舊?,這建立了一個新的函數,它名為“_”,沒有函數體,但帶有一個“Just another Perl Hacker”的原型。

如果您看了 Programming Perl,第三版(請參閱 參考資料)關于原型的實際章節,您會發現原型不能是字符串。Abigail 很隨便地忽略了這個事實(因為這個函數永遠都不會用到),然后打印出了無效的原型。

這樣合法嗎?可能吧,因為它并不引起程序崩潰。這樣瘋狂嗎?只有一點點?;褂瀉芏喔榪竦姆椒?,但這一種至少還證明了在定義函數時原型的合法性不會受到檢查。它還示范了我們可以定義一個名為“_”的函數 ?D 這種方法您不應該經常使用,因為它會和內建的“_”操作符沖突。

難看的
我們看過了良好的和糟糕的 JAPH,所剩下的就是難看的 JAPH 了。這些怪獸被精心打造,就是為了讓人們畏懼然后到處找藥吃,它們定義得太丑陋了。

下面這一段 Kickstart 編寫的 JAPH 您應該送給對您非常重要的另一半(不包括家里的寵物)。注意,稱其為一段難看的 JAPH 是不止一個原因的 ?D 四行的限制被遠遠的拋在一邊。

清單 8. 燃燒的心
#Kickstart from //www.perlmonks.com/
#note: a slight valentine variation :)
$LOVE= AMOUR.
true.cards. ecstacy.crush
.hon.promise.de .votion.partners.
tender.truelovers. treasure.affection.
devotion.care.woo.baby.ardor.romancing.
enthusiasm.fealty.fondness.turtledoves.
lovers.sentiment.worship.sweetling.pure
attachment.flowers.roses.promise.poem;
$LOVE=~ s/AMOUR/adore/g; @a=split(//,
$LOVE); $o.= chr (ord($a[1])+6). chr
(ord($a[3])+3). $a[16]. $a[5]. chr
(32). $a[0]. $a[(26+2)]. $a[27].
$a[5].$a[25]. $a[8].$a[3].chr
(32).$a[29]. $a[8].$a[3].
$a[62].chr(32).$a[62].
$a[2].$a[38].$a[4].
$a[3].´.´;
print
$o;



信不信由你,這種代碼也能運行。但是它能做什么呢?

變量 $LOVE 是揭示其神秘之處的第一把鑰匙。我們分解這段腳本以便看清 $LOVE 變量,我們把它放到一個可執行文件中,這樣我們就可以隨意進行調試。

輸出顯示(不帶插入的換行符),$LOVE 是:“ AMOURtruecardsecstacycrushhonpromisedevotionpartnerstendertrueloverstreasureaffection
devotioncarewoobabyardorromancingenthusiasmfealtyfondnessturtledovesloverssentiment
worshipsweetlingpureattachmentflowersrosespromisepoem ”,
它告訴我們所有這些不加修飾的單詞都被 Perl 作為字符串來解釋。

清單 9. 傾倒愛情
#!/usr/bin/perl
use Data::Dumper;
$LOVE= AMOUR.
true.cards. ecstacy.crush
.hon.promise.de .votion.partners.
tender.truelovers. treasure.affection.
devotion.care.woo.baby.ardor.romancing.
enthusiasm.fealty.fondness.turtledoves.
lovers.sentiment.worship.sweetling.pure
attachment.flowers.roses.promise.poem;
print Dumper $LOVE;
$LOVE=~ s/AMOUR/adore/g; @a=split(//,
$LOVE); $o.= chr (ord($a[1])+6). chr
(ord($a[3])+3). $a[16]. $a[5]. chr
(32). $a[0]. $a[(26+2)]. $a[27].
$a[5].$a[25]. $a[8].$a[3].chr
(32).$a[29]. $a[8].$a[3].
$a[62].chr(32).$a[62].
$a[2].$a[38].$a[4].
$a[3].´.´;
print
$o;



現在,我們把“AMOUR”替換成“adore”,然后將 $LOVE 分解成名為 @a 的單個字符的數組。數組 @a 中第一個元素是 “a”,第二個是“d”,依此類推組成:“ adoretruecards
ecstacycrushhonpromisedevotionpartnerstendertrueloverstreasureaffectiondevotion
carewoobabyardorromancingenthusiasmfealtyfondnessturtledovesloverssentimentworship
sweetlingpureattachmentflowersrosespromisepoem ”

最后,我們通過從 @a 數組中選取字母組成了字符串 $o。有時候我們還需要修改它們 ?D 只是為了讓事情變得有趣 ?D 但最終愛情會勝利。

拆解后的腳本是:

清單 10. 拆解后的愛情
#!/usr/bin/perl
$LOVE = "AMOURtruecardsecstacycrushhonpromisedevotionpartners".
"tendertrueloverstreasureaffectiondevotioncarewoobaby".
"ardorromancingenthusiasmfealtyfondnessturtledoveslovers".
"sentimentworshipsweetlingpureattachmentflowersroses".
"promisepoem";
$LOVE=~ s/AMOUR/adore/g;
@a=split(//, $LOVE);
$o.= chr (ord($a[1])+6). chr (ord($a[3])+3). $a[16]. $a[5] .
# j u s t
chr (32). $a[0]. $a[(26+2)]. $a[27]. $a[5].$a[25]. $a[8].
# space a n o t h e
$a[3].chr (32).$a[29]. $a[8].$a[3]. $a[62].chr(32).$a[62].
# r space p e r l space l
$a[2].$a[38].$a[4]. $a[3].´.´;
# o v e r
print $o;



真的,愛情是個謎題

自己探索 JAPH
我們已經看了各種有趣的微型腳本,還分析了很多有趣的 Perl 技巧。JAPH 肯定會是一種挑戰,所以任何解釋與您自己探索出它錯綜復雜的結構之后得到的快樂相比,都顯得蒼白無力。不過事先要警告的是,大多數 JAPH 都需要具有 Perl 方面的高級知識和一定的耐心。挑戰就在前面 ?D 不要害怕用 JAPH 去檢驗自己(參見 參考資料部分,您可以找到這些 JAPH)。

不過鼓起勇氣來,實踐確實可以讓理解 JAPH 變得更容易。簡單的技巧,如用十六進制對字符串進行編碼或改變變量 $, 都很容易上手(但是無論如何都要小心一點)。

我要感謝所有那些投入時間和精力設計 JAPH 的人們。每一個 JAPH 都會教您一些新的東西,而且可以看做是一種快樂。就我所知,沒有任何其它的語言具有這樣一種既簡潔卻又令人迷惑的形式(盡管沒有人能確認是該為它感到驕傲還是慚愧)。在許多其它的語言中也都有一些類似的編寫復雜、迷惑程序的競賽。如果您有興趣學習或者愿意參加這些競賽,請參閱 參考資料尋找入手之處。其中關于C 語言的這個競賽也是很值得關注的。

下面是一些有趣的JAPH

%%
#JoeCamel on //www.perlmonks.com/
#note: requires Perl5.6.0 or better
#!/usr/bin/perl -w
use strict;

# A tribute to one of the greatest films of all time.
my(%primate, $monolith, $evolution, $contact);

$_=´primate-> throw
( "Bone" ) ; goto;
$$monolith ; bless
%primate;$evolution
=~m/?+*/; #/*+?/m~=
*humanIntellect ++;
$Discovery =~ m . [
[::]>>=<>=<>=<>=(-)
]. ; require 2001;
exists($malfunction
)#open $podBayDoors
or die ; HAL-> sing
("Daisy");sleep()*´
;[email protected]= qw(15
1 6 4 35 1 12 2 23
2 14 1 8 2 0 5 25
1 39 3 7 2);my $God
;$monolith="******"
; my @spaceTime =
split/;/,$_ ; while
(my($space,$time )=
splice (@universe,0
,2) ) { my $journey
= shift @spaceTime;
eval " $journey; ";
$contact = substr (
[email protected], $space, $time )
; if ( $space != ((
" dimension " =~ //
) +1+4+9 ) ) {print
$contact; next; }my
$starChild=$contact
;print uc$starChild

}
%%
#!/usr/local/bin/perl

undef$/;$_=<DATA>;y/ODAn / /ds;@yoda=map{length}split;print chr
oct join(´´,splice(@yoda,0,3))-111 [email protected];
__DATA__
00O00O000O00O0000 000O DD000000O0
0DO0000000O0000O00 O00000 00O00000O0O
0000 0O0 O00 O00 00D 0DO
00O0 0O0 00D 000 DO0D00000D
0O00 DOD 000000O00000 000 O00O
DD0000D000O0 000 0O00O0000D00DO 0OD D00O000D00O0
00000DO00O0 000 000O 00D0 O0D O00000O0DO0

0O000 OD0D O00O0 0000 DDDO000000 O00O000000
0O000 O00DDO 00000 0O0D00 00O0O00000O 0O00O000000
0O0O00OD00000DDD 00O 0D0 DDD D0O 00O0D
00000O00000000 O00 DO0 D00D00O000 00D00
D0O00 O0000 000O000O00DO 000 00O0 0OD00
O00 000 0O000D000O00O0 000 0D0O000000O00O00
0 0 0O0D 0000 0O0 0O0000000O000O

[editorial note: would the author of this JAPH *please* stand up? ]
%%
#Erudil from //www.perlmonks.com/
#!/usr/bin/perl -w # camel code
use strict;

$_=´ev
al("seek40D
ATA,0, 0;");foreach(1..3)
{<DATA>;}my @camel1hump;my$camel;
my$Camel ;while( <DATA>){$_=sprintf("%-6
9s",$_);[email protected] 1=split(//);if(defined($
_=<DATA>)){@camel1hum p=split(//);}while(@dromeda
ry1){my$camel1hump=0 ;my$CAMEL=3;if(defined($_=shif
t(@dromedary1 ))&&/S/){$camel1hump+=1<<$CAMEL;}
$CAMEL--;if(d efined($_=shift(@dromedary1))&&/S/){
$camel1hump+=1 <<$CAMEL;}$CAMEL--;if(defined($_=shift(
@camel1hump))&&/S/){$camel1hump+=1<<$CAMEL;}$CAMEL--;if(
defined($_=shift(@camel1hump))&&/S/){$camel1hump+=1<<$CAME
L;;}$camel.=(split(//,"40..m`{/J47134}L^7FX"))[$camel1h
ump];}$camel.="n";}@camel1hump=split(/n/,$camel);foreach(@
camel1hump){chomp;$Camel=$_;y/LJF7173175`47/616263
06465666770/;y/12345678/JL7F17517347`/;$_=reverse;
print"$_40$Cameln";}foreach(@camel1hump){chomp;$Camel=$_;y
/LJF7173175`47/12345678/;y/12345678/JL7F175173 47`/;
$_=reverse;print"40$_$Cameln";}´;;s/s*//g;;eval; eval
("seek40DATA,0,0;");undef$/;$_=<DATA>;s/s*//g;( );;s
;^.*_;;;map{eval"print"$_"";}/.{4}/g; __DATA__ 124
1 5014540165163145401571 46401 41
40143141 1551451 54401 51155 141
147145 40151156 40141 16316 3
157143 15114116 41511 57156
40167 1511641 5040 1201
45162 1544015 1163 04014
1401 641621 41144 145
15514 1162 1534 0157
146 04011 747 1221
4515 11541 54171 40
46 01210116 316
315 714315 114
116 4145163 54
40 11115614 356
40 12516314514 440
1671 511641 50 40160
145162 155151
163163 1511
5715656
%%
#MeowChow from //www.perlmonks.com/

$ _=
qq
.CG
T--A
A---T
A----T
C----G
T----A
A---T
G--C
CG
CG
C--G
G---C
G----C
C----G
A----T
C---G
G--C
AT
CG
A--T
A---T
G----C
A----T
G----C
C---G
A--T
GC
CG
G--C
A---T
G----C
G----C
G----C
A---T
T--A
AT
CG
T--A
C---G
A----T
A----T
G----C
A---T
A--T
CG
TA
T--A
G---C
G----C
C----G
A----T
C---G
G--C
CG
TA
T--A
C---G
T----A
C----G
A----T
C---G
G--C
GC
TA
G--C
C---G
G----C
G----C
G----C
A---T
T--A
CG
AT
G--C
A---T
A----T
C----G
C----G
A---T
A--T
CG
CG
G--C
G---C
G----C
A----T
T----A
C---G
G--C
CG
TA
A--T
A---T
G----C
A----T
A----T
C---G
A--T
GC
TA
G--C
C---G
T----A
G----C
G----C
C---G
T--A
AT
CG
G--C
G---C
T----A
C----G
G----C
C---G
C--G
CG
AT
T--A
C---G
G----C
G----C
A----T
T---A
G--C
CG
TA
G--C
A---T
G----C
A----T
G----C
.;@_{A
=> C
=>
G=>
T=>}
=0..3
;s;. *
(w).*
(w).*
n;$_
{ $-
++
/9
%2?$
2:$ 1
};gex;
s;(.)(
.)(.)(.
);chr
64*$
1+
16
*$2+
4 *$
3 +$
4 ;gex
; eval

%%
#Clinton Pierce
#note: Requires 5.6.0 or better

´% * % % * % %<>
* % ~ * % % * % * * % * *
* % % * * % * % *<> * % ~ % % % * %
* * * % * % % % % * % % % % % % * % % * %
% * % % ^ * % % % % *[] % % * * % * * % % %
% * % % % % % % * * % * * @ * @ % * % %
% ^ % * % * % * * % % * % <> % % % % * % %() %
% % * * * % % * % % * * % * * * * % * * % % * * *
% * * * % % * % % *[]<> % % % % * % * * * % % *<>
% * * % % % * * % * * * * % * * * %/ # % * *
% % % * * / * *// % % <> // % %/ % // % * %
* * * || / / % %// * /<> %// %// % %<>
* % * % | | ||// % || // // % // * * * %
%{} % * ---- | / %||// / ---/ / * % % *
% * * ____ | | / / / /----/ * %
---- | / // /
/ /´
=~m/(.*)/s;$_=$1;
s![-|_/s]!!g
;%e=(´%´,0,
´^´,132918,
´~´=>18054,
´@´=>19630,
´*´ =>0b01,
´#´=>13099,
´[]´=>4278,
´<>´=>2307,
´{}´=>9814,
´()´,2076);
for $a(keys
%e){$e{$a}=
sprintf"%b"
, $e{$a};}
$y= qq{(}.join(
´|´,map "Q$_E"
,keys %e).qq{)};s/$y
/$e{$1}/gex;print pack"B*",$_;

 
Copyright © 2002-2012 www.pfynwn.com.cn. All rights reserved.
JSP中文網    備案號:粵ICP備09171188號
成都恒??萍擠⒄褂邢薰?nbsp;   成都市一環路南二段6號新瑞樓三樓8號