perl - 已解决:哈希内容访问与不同的 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
如果代码按原样运行——一切正常
$count++
现在添加如下增量就足够了,代码会产生错误
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中表现出来。
注意:问题不仅体现在,而且还体现在对-- post# 60653651$count++
旁边的哈希内容的任何其他访问上say "Person: $count";
我想听听关于这种情况的意见,原因是什么?
原因:输入数据具有DOS 形式的eol\r\n
,当在Linux chomp
中处理的数据删除时,仅\n
作为\r
字段名称的一部分(用作哈希键)。感谢Shawn指出问题的根源。
解决方案:通用修复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,并且没有适当地转换文件的行尾。
@chomp
只删除一个换行符(嗯,$/
是迂腐的当前值),所以当用于以 Windows 样式行结尾的字符串时,它会留下回车符。哈希键不是"Position"
,而是"Position\r"
,这不是其余代码使用的。
推荐阅读
- python - 抓取动态生成的 CSS 标签
- javascript - 哪些 TypeScript 标识符和构造(除了枚举)“存活”了编译并且可以在运行时在 JavaScript 中访问?
- javascript - 为什么当父 div 的高度降低到 0 时子 div 没有被删除?
- c - 如何向正在运行的 gtk 进程发送信号
- sql - Postgres 查询在执行添加时显着减慢,包括只有空值的列
- reactjs - React - 通过另一个组件调用函数
- hl7-fhir - 改进 HL7 FHIR ContactPoint Extension:电话地址示例
- java - Spring 的“@Validated”不适用于 Liberty 和注入
- ios - Swift - HTTP 摘要认证
- google-api - “此应用暂时禁用了使用 Google 登录” - 但我们未达到上限