Perl数据结构遍历——引用后跟键



结果:HASH(0x1948958) ARRAY(0x1978250) ./directory/filename多行

期望结果:[Key of first hash] [Key of second hash] ./directory/filename #(elements of array, currently working)

Catch:应该携带到N层结构,因此我尝试使用Data::Walk。

在遍历结构时,我真正想做的是引用正在使用的键。有点像Data::Dumper,但以制表符分隔,而不是代码格式。我认为可能的解决方案(按优先顺序)是:

  • 我忽略了对Data::Walk的调用。
  • 一个我不知道的更好的模块。
  • 一个可以内联
  • 的快速代码片段
  • 我自己的模块/分支Data::Walk/Data::Dumper(大皱眉头),将添加此功能。

use strict;
use File::Basename;
use Data::Walk;
my $files;
while (<>) {
        chomp;
        #ls -l output in a file; referencing filename from it (8th column)
        my @line = split(/ /, $_, 8);
        #fileparse exported by File::Basename
        my ($name,$path) = fileparse($line[7]);
        open (my $fh, '<', $path . $name);
        my $sha = Digest::SHA->new('sha1');
        $sha->addfile($fh);
        #finding files by basename, then unique hash, then however many places it is stored.
        #question not why I don't use the hash as the first field.
        #basename    digest    path
        push(@{$files->{$name}->{$sha->hexdigest}}, $path . $name);
}
my @val;
sub walkit {
        $val[$Data::Walk::depth - 1] =  $_;
        if ($Data::Walk::depth == 3) {
                print join("t", @val), "n";
        }
}
&walk (&walkit, %$files);

大师?

编辑:尽管我有更好的判断,我还是试着再回答一次这个问题。

这里有一个简单的方法来打印你想要的东西。使用Data::Walk是不可行的,因为当你在哈希中(你只是得到一个指向容器的指针)时,你没有关键上下文。

这个函数适用于比较复杂的结构。当然,如果你在里面放了一个函数引用或一些不稳定的东西,它不会给出正确的输出。

use strict;
use warnings;
my $res;
sub walk {
    my ($item, $path) = @_;
    if (ref $item eq 'ARRAY') {
        foreach (@$item) {
            walk($_, $path);
        }
    } elsif (ref $item eq 'HASH') {
        foreach (keys %$item) {
            push @$path, $_;
            walk($item->{$_}, $path);
            pop @$path;
        }
    } else {
        print join('-', @$path, $item), "n";
    }
}
my $struct = {
    a => {
            a1 => { a11 => [ 1, 2, 3 ] },
            a2 => { a22 => [5, 6, 7] }
    },
    b => { b1 => [ 99 ], },
    c => [ 100, 101, ],
    d => [ 101, { d2 => { d3 => [200, 210] }, }, ],
};
walk $struct;
for my $name (keys(%$files)) {
   for my $digest (keys(%{$files->{$name}})) {
      my @qfns = @{ $files->{$name}{$digest} };
      if (@qfns > 1) {
         say "For $name and $digest,";
         say "   $_" for @qfns;
      }
   }
}

(我假设您正在寻找重复项,所以当只有一个路径与名称-摘要组合相关联时,我不打印任何内容。如果您想打印所有内容,可以删除if

其他一些清理:

use strict;
use warnings;
use 5.010;
use Digest::SHA    qw( );
use File::Basename qw( basename );
sub calc_digest {
   my ($qfn) = @_;
   open(my $fh, '<', $qfn) or die $!;
   my $sha = Digest::SHA->new('sha1');
   $sha->addfile($fh);
   return $sha->hexdigest();
}
my $files;
while (<>) {
   my $qfn = (split)[7];
   my $name = basename($path);
   my $digest = calc_digest($qfn);
   push @{ $files->{$name}{$digest} }, $qfn;
}

("qfn"代表"限定文件名",表示文件的路径,这不是$path所包含的。即使$line[7]包含路径,您仍在重复构建路径

最新更新