Perl:从内到外打开列表不起作用?

时间:2011-04-22 20:09:48

标签: perl

$all="{this, {is, some, {deeply, nested}, text}, for, you}";
while ($all=~s/{([^{}]*?)}/f($1)/seg) {}
sub f {return \{split(",",$_[0])};}
print @{$all};

我希望$ all是listref,其列表包含:

{this, [reference to array], for, you}

相反,@ {$ all}为空。

我确信这是基本的,但我做错了什么?

注意:我故意“高举”代码在这里发布(即显示问题的最小代码)。更广泛的版本位于:https://github.com/barrycarter/bcapps/blob/master/playground.pl

编辑:感谢所有回答的人!注意:

  • 真正的f()有副作用,更新dbs等,所以我真的必须调用它。它不仅仅是 将列表更改为其他内容。我不好意思没有提到这一点。

  • 我从Mathematica导出所以“{a,b,c}”是一个列表,而不是 哈希值。再次,mea culpa没有提到这一点。

  • 我知道执行此操作的“正常”方式是递归的:处理每个 如果元素是列表,则在列表本身上调用f()。一世 试图“展开”递归以避免分裂嵌套 “{”。如果你在里面工作,你永远不必计算“{” 解析。

  • 一个有趣的其他应用程序将是一个单行的XML解析器(差不多)。

  • 给geekosaur一个勾选标记,指出哪里出错了 为什么我的方法可能是错的。

  • 我想我会尝试解析器方法甚至是jrey的s / {/ [方法。

3 个答案:

答案 0 :(得分:5)

你不能让$all同时成为一个字符串,你在上迭代匹配一个收集迭代结果的arrayref。 $all最终会变成字符串"thisARRAY(0xdeadbeef)foryou",而@$all会将其用作包符号名称,几乎肯定没有定义,因此它会自动归档为空列表

此外,{}已经是HASH而不是ARRAY)引用,因此您将SCALAR引用返回到HASH引用您显然期望的ARRAY参考。 {}在正则表达式中很特殊(foo{1,3}表示1到3次重复foo),所以你应该逃避它们。

正确的方法是收集到结果列表中,例如

my @res;
while ($all =~ /\G\{([^{}]*?)\}/sg) {
    push @res, f($1);
}

use warningsuse strict会告诉你一些错误,如果不是恰当的话。使用它们。总是

答案 1 :(得分:2)

使用解析器。

#! /usr/bin/env perl

use warnings;
use strict;

use Data::Dumper;
use Parse::RecDescent;

my $all = "{this, {is, some, {deeply, nested}, text}, for, you}";

my $p = Parse::RecDescent->new(q[
  list: '{' <commit> listitem(s /,/) '}' { $return = $item[3] }
      | <error?>
  listitem: word | list
  word: /\w+/
]);

my $l = $p->list($all);
die "$0: bad list\n" unless defined $l;

$Data::Dumper::Indent = $Data::Dumper::Terse = 1;
print Dumper $l;

输出:

[
  'this',
  [
    'is',
    'some',
    [
      'deeply',
      'nested'
    ],
    'text'
  ],
  'for',
  'you'
]

答案 2 :(得分:0)

您的文本格式很容易转换为Perl,之后您可以评估它。

#!/usr/bin/env perl
my $all = "{this, {is, some, {deeply, nested}, text}, for, you}";

$all =~ s/\s*,\s*/','/g;
$all =~ s/'?\{/['/g;
$all =~ s/\}'?/']/g;
my $result = eval $all;

use Data::Dumper;
print Dumper $result;