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++] 遍历@$a数组,返回一个元素
  2. $p += ... 该元素被添加到$p
  3. print chr( $p ... ) 然后$p返回 chr() 并打印结果字符。

sub 块中的最后一个是$j,这意味着每次迭代,sub 的返回值将是对自身的引用。这是允许半递归功能的部分。

$一个

$a是对包含 0 和输入字符串拆分结果的数组的引用。一行代码中还发生了一些事情:

  • q/43 .../这是带有分隔符斜杠的常规q()单引号字符串/]它在表示数组引用的右括号之前结束。
  • split "[: \n]+",这是对字符类的拆分,重复 1 次或多次。它里面有额外的空间(我在这里删除了)来填充 JAPH 本身的空间。基本上这会删除所有冒号、空格和换行符并返回结果列表。
  • $a = [0, ... ]拆分的列表被添加到0(只有一个元素)的列表中,并且所有内容都用括号括起来以表示数组引用,然后将其存储在$a.

我假设列表开头是0因为代码有一个一次性错误,因为它$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 += 00被添加到$p,并将 (74) 的值返回$p给 chr
  • print chr(74) 这现在打印J到标准输出
  • $j被退回。
  • ->()对返回值执行另一次执行,因此$j再次运行。
  • $a->[$h++] $h递增到 2,返回 1$a返回第二个元素,即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=Deparse以查看 Perl 看到的内容:

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 回答