如何在 Perl 中解决此警告

How to resolve this warning in Perl

我问过这类问题previously但没有提供完整的代码。

我正在阅读下面的文件并检查每列中存在的最大字宽,然后将其以适当的对齐方式写入另一个文件。

id0 id1 id2 batch
0   34  56  70
2   3647    58  72  566
4   39  616 75  98  78 78987 9876 7899 776
89  40  62  76
8   42  64  78
34  455 544 565

我的代码:

unlink "temp1.log";
use warnings;
use strict;
use feature 'say';
my $log1_file = "log1.log";
my $temp1 = "temp1.log";
open(IN1, "<$log1_file" ) or die "Could not open file $log1_file: $!";
my @col_lens;

while (my $line = <IN1>) {
    my @fs = split " ", $line;
    my @rows = @fs ;
    @col_lens =  map (length, @rows) if $.==1;
    for my $col_idx (0..$#rows) {
        my $col_len = length $rows[$col_idx];
        if ($col_lens[$col_idx] < $col_len) {
            $col_lens[$col_idx] = $col_len;
        }
    };
};
close IN1;
open(IN1, "<$log1_file" ) or die "Could not open file $log1_file: $!";
open(tempp1,"+>>$temp1") or die "Could not open file $temp1: $!";
while (my $line = <IN1>) {
    my @fs = split " ", $line;
    my @az;
    for my $h (0..$#fs) { 
        my $len = length $fs[$h]; 
        my $blk_len = $col_lens[$h]+1;
        my $right = $blk_len - $len;
        $az[$h] = (" ") . $fs[$h] . ( " " x $right );
    }
    say tempp1 (join "|",@az);
};

我的警告

Use of uninitialized value in numeric lt (<) at new.pl line 25, <IN1> line 3.
Use of uninitialized value in numeric lt (<) at new.pl line 25, <IN1> line 4.
Use of uninitialized value in numeric lt (<) at new.pl line 25, <IN1> line 4.
Use of uninitialized value in numeric lt (<) at new.pl line 25, <IN1> line 4.
Use of uninitialized value in numeric lt (<) at new.pl line 25, <IN1> line 4.
Use of uninitialized value in numeric lt (<) at new.pl line 25, <IN1> line 4.

我得到了正确的输出,但不知道如何删除这个警告。

您收到 uninitialized 警告是因为,在检查 $col_lens[$col_idx] < $col_len 条件时,其中一个或两个是 undef.

解决方案一:

您可以使用 next 语句跳过检查此条件。

for my $col_idx (0..$#rows) {
        my $col_len = length $rows[$col_idx];
        
        next unless $col_lens[$col_idx];
        
        if ($col_lens[$col_idx] < $col_len) {
            $col_lens[$col_idx] = $col_len;
        }
    }

解决方案 2:(不建议):
您只需将此行放在脚本顶部即可忽略 Use of uninitialized value.. 警告。这将禁用块中的 uninitialized 个警告。

no warnings 'uninitialized';

更多信息,请参考此link

$col_idx 最多可以是一行中的字段数减一。对于第三行,这比 @col_lens 的最高索引要多,它最多包含 3 个元素。所以做以下是没有意义的:

if ($col_lens[$col_idx] < $col_len) {
   $col_lens[$col_idx] = $col_len;
}

替换为

if (!defined($col_lens[$col_idx]) || $col_lens[$col_idx] < $col_len) {
   $col_lens[$col_idx] = $col_len;
}

有了这个,就真的没有必要再检查 $. == 1 了。

以下代码演示了解决此任务的众多可能方法之一

  • 逐行阅读
  • 获取每个字段的长度
  • 与之前存储的比较
  • 调整到最大长度
  • 形成$format打印字符串
  • 打印格式化数据
use strict;
use warnings;
use feature 'say';

my(@data,@length,$format);

while ( <DATA> ) {
    my @e = split ' ';
    my @l = map{ length } @e;
    $length[$_] = ($length[$_] // 0) < $l[$_] ? $l[$_] : $length[$_] for 0..$#e;
    push @data,\@e;
}

$format = join '  ', map{ '%'.$_.'s' } @length;
$format .= "\n";

for my $row ( @data ) {
    printf $format, map { $row->[$_] // '' } 0..$#length;;
}

__DATA__
id0 id1 id2 batch
0   34  56  70
2   3647    58  72  566
4   39  616 75  98  78 78987 9876 7899 776
89  40  62  76
8   42  64  78
34  455 544 565

输出

id0   id1  id2  batch
  0    34   56     70
  2  3647   58     72  566
  4    39  616     75   98  78  78987  9876  7899  776
 89    40   62     76
  8    42   64     78
 34   455  544    565