解析文本文件并在perl中创建复杂的树结构

时间:2014-03-17 20:04:11

标签: perl tree perl-data-structures

我有一个输入文本文件,如下所示:

DEV=T124^BRD=100^IO=HDMI^MODE=1^REG=ABC^FLD=X^VAL=200
DEV=T124^BRD=100^IO=HDMI^MODE=1^REG=ABC^FLD=Y^VAL=100
DEV=T124^BRD=100^IO=HDMI^MODE=2^REG=ABC^FLD=X^VAL=100
DEV=T124^BRD=100^IO=HDMI^MODE=2^REG=ABC^FLD=Y^VAL=200
DEV=T124^BRD=100^IO=DP^MODE=1^REG=XYZ^FLD=X^VAL=200
DEV=T124^BRD=100^IO=DP^MODE=1^REG=XYZ^FLD=Y^VAL=100
DEV=T124^BRD=100^IO=DP^MODE=1^REG=MLK^FLD=X^VAL=200
DEV=T124^BRD=100^IO=DP^MODE=1^REG=MLK^FLD=Y^VAL=100

我想解析它并将其输出到一个看起来像这样的文件:

DEV:T124
  BRD:100 
    IO:HDMI 
      MODE:1 
        REG:ABC 
          FLD:X,VAL:200                
          FLD:Y,VAL:100          
      MODE:2
        REG:ABC 
          FLD:X,VAL:100                
          FLD:Y,VAL:200          
    IO:DP 
      MODE:1 
        REG:XYZ 
          FLD:X,VAL:200                
          FLD:Y,VAL:100          
        REG:MLK 
          FLD:X,VAL:200                
          FLD:Y,VAL:100

我确实看过这个例子,但它并没有完全解决我的问题,因为Data:Dumper会将它打印成树形结构。 List of paths into hash array tree in Perl

另外,我是Perl的新手,并且不理解哈希的散列特别是在这个评论中: https://stackoverflow.com/a/13209256/3430142

我使用了该注释中发布的代码并编写了以下内容(@rows是一个包含输入文件中的行的数组)。

我不遵循foreach循环的工作方式。所以如果我将来需要改变它,我不知道该怎么做。这就是我要求替代实现的原因,我可以自定义/理解而不是依赖于该代码。

我使用了一些Dumper方法来编辑某些东西。我还用Tie来删除大括号和引号。

open TREE, "+>", $ARGV[1] or die $!;
my $tree = {"" => {}};
foreach my $input (@rows) { 
    chomp $input;       
    my $t = $tree;
    $t = $t->{$_} //= {} for split /\^/ => $input;
}

$Data::Dumper::Indent = 1;
$Data::Dumper::Sortkeys = 1;
$Data::Dumper::Useqq = 1;
$Data::Dumper::Varname = "PROD";
$Data::Dumper::Terse = 1;
$Data::Dumper::Purity  = 1;
$Data::Dumper::Sparseseen = 1;
$Data::Dumper::Sortkeys = 1;
$Data::Dumper::Pair = "";
$Data::Dumper::Quotekeys = 1;

print TREE Dumper $tree;
close TREE;

tie @PST, 'Tie::File', $ARGV[1] or die $!;
for (@PST) {
    s/[\{\},"]//g;
}
untie @PST;

输出如下:

DEV:T124
  BRD:100 
    IO:HDMI 
      MODE:1 
        REG:ABC 
          FLD:X
            VAL:200   



          FLD:Y
            VAL:100     



      MODE:2
        REG:ABC 
          FLD:X
            VAL:100    



          FLD:Y
            VAL:200     




    IO:DP 
      MODE:1 
        REG:XYZ 
          FLD:X
            VAL:200                



          FLD:Y
            VAL:100          



        REG:MLK 
          FLD:X
            VAL:200            



          FLD:Y
            VAL:100

正如你所看到的,我无法摆脱通过删除花括号创建的新行,而且我也无法获得我想要的结构,因为Dumper已经创建了预定义树。 / p>

感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

您不需要任何外部模块,甚至任何复杂的数据结构。你需要的只是数组。一个用于保存当前行的数据,另一个用于保存上一行的数据以进行比较。

以下脚本几乎可以展示您的需求,但您必须根据数据和输入/输出方法进行调整:

use strict;
use warnings;

my @prev;

while (<DATA>) {
    chomp;
    my @data = split;
    for my $i (0..$#data) {
        if (! $prev[$i] || $data[$i] ne $prev[$i]) {
            @prev = ();
            print '' . ('  ' x $i) . $data[$i] . "\n";
        }
    }
    @prev = @data;
}

__DATA__
step1a step2a step3a step4a step5a step6a
step1a step2a step3a step4a step5a step6b
step1a step2a step3a step4b step5a step6a
step1a step2a step3a step4b step5a step6b
step1a step2a step3b step4a step5b step6a
step1a step2a step3b step4a step5b step6b
step1a step2a step3b step4a step5c step6a
step1a step2a step3b step4a step5c step6b

输出

step1a
  step2a
    step3a
      step4a
        step5a
          step6a
          step6b
      step4b
        step5a
          step6a
          step6b
    step3b
      step4a
        step5b
          step6a
          step6b
        step5c
          step6a
          step6b

答案 1 :(得分:0)

如果您可以使用已排序的键,则在创建$tree之后,以下内容将根据您创建哈希的方式主要执行您想要的操作:

dump_tree($tree);

sub dump_tree {
    my ($hashR, $indent) = @_;

    $indent ||= 0;          # In case use warnings
    foreach my $key (sort keys %$hashR) {
        (my $print_key = $key) =~ s/=/:/;
        print TREE ((' ' x $indent), "$print_key\n");
        dump_tree($hashR->{$key}, $indent+2);
    }
}
但是,它并没有像你的例子那样加倍同一行的FLD:,VAL:。这应该是一个相对简单的补充,你可以在递归到dump_tree之前检查你是否只有一个更深层次的单一密钥。