1

このコードがその出力をどのように出力するかを誰か説明できますか?

コード

#!/usr/bin/perl
use warnings;
use strict;
       my          
      ($j,$        
   a,$p,$h);$      
   j=sub{print(    
  chr($p+=$a->[$   
  h++]));$j};;;$a  
 =[0,        split 
 "[:         \n]+", 
q/43         -002:1
-084         065:13
0001         000005
-0012        -00003
000013   -82 00048 
21:13:-6.00:-76:72 
 -007.:02:00008.00 
  :::-6.00:::013  
  -70:3::-70:.64   
    /];$p=0x4a     
      ;;$h=0;      
$j->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->();

出力:

Just another perl hacker

4

3 に答える 3

6

これは実際にはかなり単純な JAPH です。その最大の特徴は、「画像」の大部分を占めるデータ列の分割と、半再帰的な印刷です。

これは、フォーマットをクリーンアップしたときに取得するコードです

my ($j,$a,$p,$h);
$j = sub {
    print( chr( $p += $a->[$h++] ) );
    $j
};
;;

$a = [0, split "[: \n]+",   # the split regex
q/43         -002:1         # input string start: q/ ...
-084         065:13
0001         000005
-0012        -00003
000013   -82 00048 
21:13:-6.00:-76:72 
 -007.:02:00008.00 
  :::-6.00:::013  
  -70:3::-70:.64   
    /];                     # input string end:   .../   
# print Dumper $a;  # <--- this is my line
$p = 0x4a;;
$h=0;      

$j->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->();

最初の部分は、4 つの主要な変数の宣言と割り当てです。

$j

$j文字を出力し、それ自体への参照を返すコード参照です。印刷はいくつかのステップで構成されています。

  1. $a->[$h++] 配列を繰り返し処理し、@$a1 つの要素を返します
  2. $p += ... その要素が追加されます$p
  3. print chr( $p ... ) その後$p、 chr() に返され、結果の文字が出力されます。

サブブロックの最後は です$j。これは、各反復を意味し、サブの戻り値はそれ自体への参照になります。これは、半再帰機能を可能にする部分です。

$a

$a0 と入力文字列の分割の結果で構成される配列への参照です。ここでも、1 行のコードでいくつかのことが起こっています。

  • q/43 .../これは、区切り文字スラッシュを含む通常のq()一重引用符で囲まれた文字列/です。]配列参照を示す閉じ括弧の直前で終了します。
  • split "[: \n]+",これは文字クラスの分割であり、1 回以上繰り返されます。JAPH 自体のスペースを埋めるために、その中に余分なスペースがあります (ここでは削除しました)。基本的に、これによりすべてのコロン、スペース、および改行が削除され、結果のリストが返されます。
  • $a = [0, ... ]分割のリストは0(1 つの要素のみ) のリストに追加され、配列参照を示すためにすべてが角かっこで囲まれ、$a.

0コードに1回限りのエラーがあるため、リストは で始まると思い$pます。元の値は出力の最初の文字です。

これは次のData::Dumper出力です$a

$VAR1 = [
          0,
          '43',
          '-002',
          '1',
          '-084',
          '065',
          '13',
          '0001',
          '000005',
          '-0012',
          '-00003',
          '000013',
          '-82',
          '00048',
          '21',
          '13',
          '-6.00',
          '-76',
          '72',
          '-007.',
          '02',
          '00008.00',
          '-6.00',
          '013',
          '-70',
          '3',
          '-70',
          '.64'
        ];

$p と $h

$p$hは数値のみであり、これにおけるそれらの役割は、それぞれ関数のソース番号と配列chr()の反復子です。@$a

最後の行は、$jサブルーチンが実行され、JAPH が出力される部分です。連鎖->()構文は、前の各反復の戻り値が次の実行に使用されることを意味します。そして$j、それ自体への参照を返します。これにより、半再帰的な問題が発生し、値のみが変更されます。

これを行うのと似ていると思います:

$x = $j->();
$y = $x->();
$z = $y->();
...

それでは、最初のいくつかの手順を見てみましょう

  • $j->()実行
  • $a->[$h++] $hは 1 にインクリメントされ、サブストリップに 0 を返します。$aサブストリップは の最初の要素である を返し$aます0
  • $p += 0これ0を に加算し、 (74)$pの値を chr に戻します。$p
  • print chr(74) これによりJ、標準出力に a が出力されるようになりました
  • $j返されます。
  • ->()戻り値に対して別の実行が実行されるため、$j再度実行されます。
  • $a->[$h++] $hは 2 にインクリメントされ、1$aが返され、2 番目の要素である が返されます43
  • $p += 4374 + 43 = 117 が返されますchr
  • print chr(117)これは印刷しますu

の要素は$a正と負の両方であり、必要な場所に数値を移動します。最終的に、印刷されたすべての文字は次のようになります。Just another Perl hacker,

最初の10回の実行の概要は次のとおりです。

p => 74  += 0         =  74 output => chr( 74) J
p => 74  += 43        = 117 output => chr(117) u
p => 117 += -002      = 115 output => chr(115) s
p => 115 += 1         = 116 output => chr(116) t
p => 116 += -084      =  32 output => chr( 32)
p => 32  += 065       =  97 output => chr( 97) a
p => 97  += 13        = 110 output => chr(110) n
p => 110 += 0001      = 111 output => chr(111) o
p => 111 += 000005    = 116 output => chr(116) t
p => 116 += -0012     = 104 output => chr(104) h
于 2013-03-06T15:08:48.123 に答える
5

で実行して、perl -MO=DeparsePerl が何を認識しているかを確認します。

use warnings;
use strict 'refs';
my($j, $a, $p, $h);
$j = sub {
    print chr($p += $$a[$h++]);
    $j;
}
;
$a = [0, split(/[:         \n]+/, "43         -002:1\n-084         065:13\n0001         000005\n-0012        -00003\n000013   -82 00048 \n21:13:-6.00:-76:72 \n -007.:02:00008.00 \n  :::-6.00:::013  \n  -70:3::-70:.64   \n    ", 0)];
$p = 74;
$h = 0;
&$j()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->()->();

基本的に$jは、別のサブ参照などを返すサブ参照です。戻る前に、文字を出力し、「ポインタ」を文字の配列に移動して出力します。

于 2013-03-06T12:38:11.387 に答える
1

小さなコメント。

数字ブロックの最後の行はこれである必要があります

-68:3::-70:.64

それ以外の

-70:3::-70:.64   

ピリオドを印刷するには-68が必要で、-70はコンマを印刷していました。

(行の残りの部分、 ":3 ::-70:.64"は単なるノイズです。これらの数値は、$ jの無名関数に渡されることはありません。)

于 2013-03-06T21:49:57.270 に答える