在散列中添加键值对,通过在值中指定数组=>不能将未定义的值用作ARRAY引用

问题描述 投票:1回答:2

我正在尝试将散列键值对中的数组指定为键的值。在分配之后,我正在尝试取消引用它并从输出文件中的特定键打印数组值,如下面的代码所示。

代码在数组操作部分上运行不正常。有人能告诉我我做错了什么吗?

use strict; 
use warnings;
use Data::Dumper;

# File input
my $in_file = 'log.txt';

# Output file
my $out_file_name = 'output.csv';

open(my $fout, '>', $out_file_name);
# print header csv
print $fout "Col1\,Col2\,Col3\,Col4\,Col5\n";

# Read the input file
open(FH, '<', $in_file) or die "Could not open file '$in_file' $!";
my @log_file = <FH>;
# print Dumper(@log_file),"\n";
close (FH);

# my @test_val;

my ($read, $ref, $val_county, $val_rec, $val_tar, $val_print, @test_values, $status);

foreach(@log_file) {
    # print $_;
    if ($_ =~ /\t+(?<county_name>(?!Total).+)\s+/i) {           
        $ref->{code} = $+{county_name};
        $val_county = $ref->{code};
    } elsif ($_ =~ /^Total\s+records\s+in\s+TAR\s+\(pr.+\)\:\s+(?<tar_records>.+)$/i) {
        $ref->{code} = $val_county;
        push(@test_values, $+{tar_records});
        $ref->{tar_rec} = \@test_values;
        # $val_rec = $ref->{tar_rec};
        # $val_rec =~ s/\.//g;
    }

    &print_file($ref);

}


sub print_file {
    my $ref = shift;    
    my $status = shift; 
    print $fout join(",", $ref->{code}, [@{$ref->{tar_rec}}]), "\n";  # Line 68
    print Dumper($ref);
}

close $fout;

print "Done!","\n";

该代码提供了如下错误:“不能在test_array_val_hash.pl第68行使用未定义的值作为ARRAY引用。”

arrays perl hash error-handling scripting
2个回答
-1
投票

问题是你在错误的地方打电话给print_file

想象一下,您一次解析一行文件。您的代码解析第一行并填充$ref->{code}。但是你在一个部分填充的print_file上调用$ref所以它不起作用。

您的代码也没有重置任何使用的变量,因此当它在文件中前进时,$ref的内容将会增长。

下面的代码通过在$ref->{tar_rec}中隐式设置一个空数组来修复第一个问题,并且只在记录开始新记录时或者在文件中完成读取时才打印出来。由于$ref->{tar_rec}是一个数组,它通过允许你直接推入它而不是依靠@test_values来解决另一个问题。为了增加安全性,它为$ref分配了一个空哈希。

if(open(my $fh, '<', $in_file)) {
    my $ref;
    my $val_county;

    foreach(<$fh>) {
        # print $_;
        if ($_ =~ /\t+(?<county_name>(?!Total).+)\s+/i) {
            if(defined($val_county)) {
                print_file($ref);
            }

            $ref={};
            $val_county = $+{county_name};
            $ref->{code} = $val_county;
            $ref->{tar_rec} = [];
        } elsif ($_ =~ /^Total\s+records\s+in\s+TAR\s+\(pr.+\)\:\s+(?<tar_records>.+)$
            push @{$ref->{tar_rec}}, $+{tar_records};
        }
    }
    if(defined($ref)) {
        print_file($ref);
    }
    close($fh);

} else {
    die "Could not open file '$in_file' $!";
}

您还错误地打印出阵列

print $fout join(",", $ref->{code}, [@{$ref->{tar_rec}}]), "\n";

你不需要围绕@{$ref->{tar_rec}}的任何括号 - 它将被视为一个值列表,以传递给join原样。

print $fout join(",", $ref->{code}, @{$ref->{tar_rec}}), "\n";

0
投票

在forloop块中的第二个正则表达式匹配之前,$ref->{tar_rec}键不会被赋值 - 并且将是未定义的。以下代码段 - 基于您自己的代码 - 突出显示了该问题。

#!/usr/bin/perl -w

my @tar_records = (15,35,20);

my $ref = {
    code => 'Cork',
    tar_rec => \@tar_records,
};

sub print_info {
    my $ref = shift;
    print join(", ", $ref->{code}, (@{$ref->{tar_rec}})), $/;
}

print_info($ref);

# Once we 'undefine' the relevant key, we witness the afore-
#  mentioned error.
undef $ref->{tar_rec};

print_info($ref);

要避免此错误,可以在for循环之前为$ref->{tar_rec}键指定匿名数组引用(因为$ref->{tar_rec}是累积值)。

# Be sure not to declare $ref twice!
my ($read, $val_county, $val_rec, $val_tar, $val_print, @test_values, $status);
my $ref = {
    code => '',
    tar_rec => [],
}

附:另请注意,我在join()函数中使用了圆括号而不是方括号(尽管您实际上并不需要)。

© www.soinside.com 2019 - 2024. All rights reserved.