Perl :从递归调用中捕获数据



我编写了一个函数来接收数组数组,并将其打印为没有标签的XML格式。当我将缓冲区字符串变量保持全局时,该函数有效。但是由于我想避免不良做法,因此我试图将其传递给函数。我提供了一个显示所有案例的 MWE。

输入:

( "main",
["fred", 
["barney"] ],
["george", 
["jane", 
["elroy"] ] ],
["homer", 
["marge", 
["bart"] ] ]
);

这基本上代表了一个树结构,如果我可以这么称呼它的话。它存储几个文件夹的层次结构。

我的正确输出 -

name my_gen_XML;

name "main";
name "fred";
name "barney";
name
name
name "george";
name "jane";
name "elroy";
name
name
name
name "homer";
name "marge";
name "bart";
name
name
name

输出错误 -

name my_gen_XML;

name "main";
name
name
name

在下面的代码片段中,我提到了 2 种称为工作和非工作的情况。工作案例产生正确的输出。非工作案例提供了错误的输出。

我的部分代码 -

#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;        
my @test = ( "main",
["fred", 
["barney"] ],
["george", 
["jane", 
["elroy"] ] ],
["homer", 
["marge", 
["bart"] ] ]
);
my $testRef = @test;
## Working - Case
#my $strBuffer;
my $final = constructTree($testRef,"    name");
print "$final n";
# Name : constructTree
sub constructTree {
my ($test, $indentStr) = @_;
my $strBuffer = "";
## Non-Working Case
$strBuffer = populateTree($test, $indentStr, $strBuffer);
## Working - Case
#$strBuffer = populateTree($test, $indentStr);
$strBuffer = "name my_gen_XML;nnn".$strBuffer;
return $strBuffer;
}
# Name : populateTree
sub populateTree {
## Non-Working Case
my ($array, $indentText, $strBuffer) = @_;
## Working - Case
#my ($array, $indentText) = @_;
my @list = @$array;
$strBuffer .= "    $indentText "$list[0]";n";
$indentText = "    $indentText";
shift(@list);
foreach my $child ( @list ) {
## Non-Working Case
populateTree(@$child, $indentText, $strBuffer);
## Working - Case
#populateTree(@$child, $indentText);
$strBuffer .= "    $indentTextn";
}
return $strBuffer;
}

我尝试使用状态变量进行$strBuffer但无济于事。我还尝试捕获递归函数的输出,但这重复了我的情况。还尝试使用临时变量,但对我的情况也没有帮助。

我想知道如何使用"非工作代码"获得"正确的输出"。我认为这是一个简单的修复,但我不确定。

下面是一个传递$strBuffer作为参考的示例:

sub constructTree {
my ($test, $indentStr) = @_;
my $strBuffer = "";
my $strBufferRef = populateTree($test, $indentStr, $strBuffer);
$strBuffer = "name my_gen_XML;nnn".$$strBufferRef;
return $strBuffer;
}
sub populateTree {
my ($array, $indentText, $strBuffer) = @_;
my $item = shift @$array;
$$strBuffer .= "    $indentText "$item";n";
my $newIndentText = "    $indentText";
foreach my $child ( @$array ) {
populateTree($child, $newIndentText, $strBuffer);
$$strBuffer .= "    $indentTextn";
}
return $strBuffer;
}

输出

name my_gen_XML;

name "main";
name "fred";
name "barney";
name
name
name "george";
name "jane";
name "elroy";
name
name
name
name "homer";
name "marge";
name "bart";
name
name
name

语句my ($foo, $bar) = @_;将 @_ 的每个元素复制到这些变量。这意味着,如果其中一个元素是字符串,则其值将复制到变量中,并且更改该变量不会更改原始变量。

除了将标量引用传递给字符串而不是字符串本身之外,正如另一个答案(我推荐(中所述,您可以使用 Perl 的别名行为,但这通常不是众所周知的行为,因此读者可能不太清楚(注释可能在这里有用(。

@_本身的元素不是副本,而是别名,因此您可以通过直接访问该元素来修改原始值,而不是将其复制到另一个变量,但这不是很好读。

sub populateTree {
my ($array, $indentText) = @_;
my $item = shift @$array;
$_[2] .= "    $indentText "$item";n";
my $newIndentText = "    $indentText";
foreach my $child ( @$array ) {
populateTree($child, $newIndentText, $_[2]);
$_[2] .= "    $indentTextn";
}
return $_[2];
}

在最新版本的Perl(5.22+(上,有一个实验性的功能称为refaliasing,它允许你轻松创建自己的别名变量。

use experimental 'refaliasing';
sub populateTree {
my ($array, $indentText) = @_;
my $strBuffer = $_[2];
my $item = shift @$array;
$strBuffer .= "    $indentText "$item";n";
my $newIndentText = "    $indentText";
foreach my $child ( @$array ) {
populateTree($child, $newIndentText, $strBuffer);
$strBuffer .= "    $indentTextn";
}
return $strBuffer;
}

CPAN 模块 Data::Alias 允许你在任何版本的 Perl 上执行此操作。

use Data::Alias;
sub populateTree {
my ($array, $indentText) = @_;
alias my $strBuffer = $_[2];
my $item = shift @$array;
$strBuffer .= "    $indentText "$item";n";
my $newIndentText = "    $indentText";
foreach my $child ( @$array ) {
populateTree($child, $newIndentText, $strBuffer);
$strBuffer .= "    $indentTextn";
}
return $strBuffer;
}

最后,你可以(ab(使用 foreach 循环的混叠行为,以一种稍微奇怪(但更兼容(的方式制作自己的别名。

sub populateTree {
my ($array, $indentText) = @_;
foreach my $strBuffer ($_[2]) {
my $item = shift @$array;
$strBuffer .= "    $indentText "$item";n";
my $newIndentText = "    $indentText";
foreach my $child ( @$array ) {
populateTree($child, $newIndentText, $strBuffer);
$strBuffer .= "    $indentTextn";
}
return $strBuffer;
}
}

相关内容

最新更新