已解决:哈希内容访问与不同的perl版本不一致 [英] SOLVED: Hash content access is inconsistent with different perl version

查看:79
本文介绍了已解决:哈希内容访问与不同的perl版本不一致的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 perl 5.22.1 perl 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

如果代码按原样运行-一切正常

If the code run as it is -- everything works fine

现在,在波纹管中添加$count++增量就足够了,并且代码会产生错误

Now it is sufficient to add $count++ increment as bellow and 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 .

This problem does not manifest itself in perl 5.30.0 (Windows 10, Strawberry Perl) or Perl v5.24.2.

注意:问题不仅通过$count++出现,而且以其他任何方式访问say "Person: $count";-

Note: the problem manifests itself not only with $count++ but with any other access to content of the hash next to say "Person: $count"; -- post# 60653651

我想听听关于这种情况的评论,原因是什么?

I would like to hear comments on this situation, what is the cause?

原因::输入数据以DOS形式\r\n出现 eol ,并且在 Linux chomp中处理的数据仅删除\n\r保留为字段名称的一部分(用作哈希键).感谢肖恩指出问题的根源.

CAUSE: input data have eol in DOS form \r\n and when data processed in Linux chomp removes only \n leaving \r as part of the field name (used as hash key). Thanks goes to Shawn for pointing out the source of the issue.

解决方案:通用修复snip_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

推荐答案

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

I can replicate this behavior by (On linux) first converting the source file to have Windows-style \r\n line endings and then trying to run it. I thus suspect that in your testing of various versions you're using Windows sometimes, and a Linux/Unix other times, and not converting the file's line endings appropriately.

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

@chomp only removes a newline character (Well, the current value of $/ to be pedantic), so when used on a string with a Windows style line ending in it, it leaves the carriage return. The hash key is not "Position", it's "Position\r", which is not what the rest of your code uses.

这篇关于已解决:哈希内容访问与不同的perl版本不一致的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆