已解决:散列内容访问与不同的Perl版本不一致

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

[在perl 5.22.1perl 5.30.0中使用以下代码遇到了一个有趣的问题

use strict;
use warnings;
use feature 'say';

#use Data::Dumper;

my %hash;
my %seen;
my @header = split ',', <DATA>;

chomp @header;

while(<DATA>) {
    next if /^\s*$/;
    chomp;
    my %data;
    @data{@header} = split ',';

    push @{$hash{person}}, \%data;
    push @{$hash{Position}{$data{Position}}}, "$data{First} $data{Last}";
    if( ! $seen{$data{Position}} ) {
        $seen{$data{Position}} = 1;
        push @{$hash{Role}}, $data{Position};
    }
}

#say Dumper($hash{Position});

my $count = 0;
for my $person ( @{$hash{person}} ) {
    say "Person: $count";
    say "Role: $person->{Position}";
}

say "---- Groups ----\n";

while( my($p,$m) = each %{$hash{Position}} ) {
    say "-> $p";
    my $members = join(',',@{$m});
    say "-> Members: $members\n";
}

say "---- Roles ----";

say '-> ' . join(', ',@{$hash{Role}});

__DATA__
First,Last,Position
John,Doe,Developer
Mary,Fox,Manager
Anna,Gulaby,Developer

如果代码按原样运行-everything works fine

现在将$count++增量添加为波纹管和code produces errors就足够了>

my $count = 0;
for my $person ( @{$hash{person}} ) {
    $count++;
    say "Person: $count";
    say "Role: $person->{Position}";
}

错误:

Error(s), warning(s):
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 22, <DATA> line 2.
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 23, <DATA> line 2.
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 24, <DATA> line 2.
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 22, <DATA> line 3.
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 23, <DATA> line 3.
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 22, <DATA> line 4.
Use of uninitialized value $data{"Position"} in hash element at source_file.pl line 23, <DATA> line 4.
Use of uninitialized value in concatenation (.) or string at source_file.pl line 35, <DATA> line 4.
Use of uninitialized value in concatenation (.) or string at source_file.pl line 35, <DATA> line 4.
Use of uninitialized value in concatenation (.) or string at source_file.pl line 35, <DATA> line 4.
Use of uninitialized value in join or string at source_file.pl line 48, <DATA> line 4.

此问题不会在perl 5.30.0(Windows 10,Strawberry Perl)或Perl v5.24.2中显现出来。

注意:

问题不仅通过$count++显现出来,而且以其他任何方式访问say "Person: $count";-post# 60653651]之后的哈希值也显示出来。

我想听听对此情况的评论,原因是什么?

CAUSE:

输入数据以DOS形式\r\n具有eol,并且在Linux中处理的数据时,chomp仅删除\n,而将\r作为字段名称的一部分(用作哈希键)。感谢Shawn指出问题的根源。

SOLUTION:

通用fixsnip_eol($arg)子例程的形式实现
use strict;
use warnings;
use feature 'say';

my $debug = 0;

say "
Perl:  $^V
OS: $^O
-------------------
" if $debug;

my %hash;
my %seen;
my @header = split ',', <DATA>;

$header[2] = snip_eol($header[2]);        # problem fix

while(<DATA>) {
    next if /^\s*$/;

    my $line = snip_eol($_);              # problem fix

    my %data;
    @data{@header} = split ',',$line;

    push @{$hash{person}}, \%data;
    push @{$hash{Position}{$data{Position}}}, "$data{First} $data{Last}";
    if( ! $seen{$data{Position}} ) {
        $seen{$data{Position}} = 1;
        push @{$hash{Role}}, $data{Position};
    }
}

#say Dumper($hash{Position});

my $count = 0;
for my $person ( @{$hash{person}} ) {
    $count++;
    say "-> Name:   $person->{First} $person->{Last}";
    say "-> Role:   $person->{Position}\n";
}

say "---- Groups ----\n";

while( my($p,$m) = each %{$hash{Position}} ) {
    say "-> $p";
    my $members = join(',',@{$m});
    say "-> Members: $members\n";
}

say "---- Roles ----";

say '-> ' . join(', ',@{$hash{Role}});

sub snip_eol {
    my $data = shift;                      # problem fix

    #map{ say "$_ => " . ord } split '', $data if $debug;
    $data =~ s/\r// if $^O eq 'linux';
    chomp $data;
    #map{ say "$_ => " . ord } split '', $data if $debug;

    return $data;
}

__DATA__
First,Last,Position
John,Doe,Developer
Mary,Fox,Manager
Anna,Gulaby,Developer

我遇到了一个有趣的问题,在perl 5.22.1和perl 5.30.0中使用以下代码使用strict;使用警告;使用功能“说”; #use Data :: Dumper;我的%hash;我的%seen;我的@header = ...

perl hash spoiling
1个回答
2
投票

我可以通过(在Linux上)首先将源文件转换为Windows样式的\r\n行尾,然后尝试运行它来复制此行为。因此,我怀疑在测试各种版本时,有时会使用Windows,而在其他时候则使用Linux / Unix,并且没有正确转换文件的行尾。

@chomp仅删除换行符(Well,$/的当前值是多余的),因此,在以Windows样式行结尾的字符串上使用时,它将保留回车符。哈希键不是"Position",而是"Position\r",这不是其余代码使用的键。

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