如何在Perl中实现哈希元素的同行对齐打印?
Perl哈希数组输出列错位问题修复
问题描述
编写Perl脚本读取多个CSV文件并将数据存入哈希数组(HoA),但输出时各列元素错位分行,无法实现对应列元素在同一行对齐展示。
原代码
#!/usr/bin/perl #use Data::Dumper; my $file3 = 'file1.csv'; my $file2 = 'file2.csv'; my $file1 = 'file3.csv'; open (my $fh_dest, ">", "outputfile.csv") or die "Can't open > outputfile.csv: $!"; my %HoA1; my %HoA2; my %HoA3; open (MODIFIED_FILE2, $file1) or die ("Could not open $file1!"); while(<MODIFIED_FILE2>){ chomp; my ($k, $v1,$v2,$v3,$v4) = split /,/,$_,5; push @{$HoA1{'MODIFIED_FILE2'}{$k}},$v1,$v2,$v3,$v4; } close(MODIFIED_FILE2); open (MODIFIED_FILE1, $file2) or die ("Could not open $file2!"); while(<MODIFIED_FILE1>){ chomp; my ($k, $v1,$v2,$v3) = split /,/,$_,4; push @{$HoA2{'MODIFIED_FILE1'}{$k}},$v1,$v2,$v3; } close(MODIFIED_FILE1); open (BASE_FILE, $file3) or die ("Could not open $file3!"); while(<BASE_FILE>){ chomp; my ($k, $v1,$v2,$v3) = split /,/,$_,4; push @{$HoA3{'BASE_FILE'}{$k}},$v1,$v2,$v3; } close(BASE_FILE); #print $fh_dest Dumper \%HoA; foreach my $MODIFIED_FILE2 (keys %{ $HoA1{'MODIFIED_FILE2'} }) { if (exists $HoA3{'BASE_FILE'}{$MODIFIED_FILE2}) { print $fh_dest "-" x 60, "\n"; print $fh_dest "$MODIFIED_FILE2\nMODIFIED_FILE2 MODIFIED_FILE1 BASE_FILE\n"; print $fh_dest "-" x 60, "\n"; foreach my $class_BASE_FILE ( @{$HoA3{'BASE_FILE'}{$MODIFIED_FILE2}} ) { printf $fh_dest "%-20s%-20s%s\n",$class_MODIFIED_FILE2,$class_MODIFIED_FILE1,$class_BASE_FILE; } foreach my $class_MODIFIED_FILE1 ( @{$HoA2{'MODIFIED_FILE1'}{$MODIFIED_FILE2}} ) { printf $fh_dest "%-20s%s\n",$class_MODIFIED_FILE2,$class_MODIFIED_FILE1; } foreach my $class_MODIFIED_FILE2 ( @{$HoA1{'MODIFIED_FILE2'}{$MODIFIED_FILE2}} ) { printf $fh_dest "%s\n",$class_MODIFIED_FILE2; } print $fh_dest "\n"; } elsif (exists $HoA2{'MODIFIED_FILE1'}{$MODIFIED_FILE2}) { print $fh_dest "-" x 60, "\n"; print $fh_dest "$MODIFIED_FILE2\nMODIFIED_FILE2 MODIFIED_FILE1 BASE_FILE\n"; print $fh_dest "-" x 60, "\n"; foreach my $class_MODIFIED_FILE1 ( @{$HoA2{'MODIFIED_FILE1'}{$MODIFIED_FILE2}} ) { printf $fh_dest "%-20s%s\n",$class_MODIFIED_FILE2,$class_MODIFIED_FILE1; } foreach my $class_MODIFIED_FILE2 ( @{$HoA1{'MODIFIED_FILE2'}{$MODIFIED_FILE2}} ) { printf $fh_dest "%s\n",$class_MODIFIED_FILE2; } print $fh_dest "\n"; } else { print $fh_dest "-" x 60, "\n"; print $fh_dest "$MODIFIED_FILE2\nMODIFIED_FILE2 MODIFIED_FILE1 BASE_FILE\n"; print $fh_dest "-" x 60, "\n"; foreach my $class_MODIFIED_FILE2 ( @{$HoA1{'MODIFIED_FILE2'}{$MODIFIED_FILE2}} ) { printf $fh_dest "%s\n",$class_MODIFIED_FILE2; } print $fh_dest "\n"; } } close ($fh_dest);
当前输出
------------------------------------------------------------ Dora MODIFIED_FILE2 MODIFIED_FILE1 BASE_FILE ------------------------------------------------------------ 34 Malaysian Malay 34 Malaysian Arab B- ------------------------------------------------------------ Boszor MODIFIED_FILE2 MODIFIED_FILE1 BASE_FILE ------------------------------------------------------------ 91 Mexico Chinese 91 Mexico Chinese 91 Mexico Chinese AB+ ------------------------------------------------------------ Szundi MODIFIED_FILE2 MODIFIED_FILE1 BASE_FILE ------------------------------------------------------------ 23 German Indian 23 German Indian 23 German Indian AB-
期望输出
----------------------------------------------------------- Dora MODIFIED_FILE2 MODIFIED_FILE1 BASE_FILE ------------------------------------------------------------ 34 34 Malaysian Malaysian Malay Arab B- ------------------------------------------------------------ Boszor MODIFIED_FILE2 MODIFIED_FILE1 BASE_FILE ------------------------------------------------------------ 91 91 91 Mexico Mexico Mexico Chinese Chinese Chinese AB+ ------------------------------------------------------------ Szundi MODIFIED_FILE2 MODIFIED_FILE1 BASE_FILE ------------------------------------------------------------ 23 23 23 German German German Indian Indian Indian AB-
问题原因及修复方案
问题根源
原代码用三个独立的foreach循环分别打印三列数据,导致每列的行依次输出,无法对齐;同时存在未定义变量直接使用的错误。
修复后的代码
#!/usr/bin/perl #use Data::Dumper; my $file3 = 'file1.csv'; my $file2 = 'file2.csv'; my $file1 = 'file3.csv'; open (my $fh_dest, ">", "outputfile.csv") or die "Can't open > outputfile.csv: $!"; my %HoA1; my %HoA2; my %HoA3; open (MODIFIED_FILE2, $file1) or die ("Could not open $file1!"); while(<MODIFIED_FILE2>){ chomp; my ($k, $v1,$v2,$v3,$v4) = split /,/,$_,5; push @{$HoA1{'MODIFIED_FILE2'}{$k}},$v1,$v2,$v3,$v4; } close(MODIFIED_FILE2); open (MODIFIED_FILE1, $file2) or die ("Could not open $file2!"); while(<MODIFIED_FILE1>){ chomp; my ($k, $v1,$v2,$v3) = split /,/,$_,4; push @{$HoA2{'MODIFIED_FILE1'}{$k}},$v1,$v2,$v3; } close(MODIFIED_FILE1); open (BASE_FILE, $file3) or die ("Could not open $file3!"); while(<BASE_FILE>){ chomp; my ($k, $v1,$v2,$v3) = split /,/,$_,4; push @{$HoA3{'BASE_FILE'}{$k}},$v1,$v2,$v3; } close(BASE_FILE); foreach my $key (keys %{ $HoA1{'MODIFIED_FILE2'} }) { print $fh_dest "-" x 60, "\n"; print $fh_dest "$key\nMODIFIED_FILE2 MODIFIED_FILE1 BASE_FILE\n"; print $fh_dest "-" x 60, "\n"; # 获取三个数组的引用,不存在则设为空数组 my $arr1 = $HoA1{'MODIFIED_FILE2'}{$key} // []; my $arr2 = $HoA2{'MODIFIED_FILE1'}{$key} // []; my $arr3 = $HoA3{'BASE_FILE'}{$key} // []; # 取最大数组长度,确保所有行都被处理 my $max_len = scalar @$arr1; $max_len = scalar @$arr2 if scalar @$arr2 > $max_len; $max_len = scalar @$arr3 if scalar @$arr3 > $max_len; # 按索引遍历,同一行打印三列对应元素 for my $i (0..$max_len-1) { my $val1 = $arr1->[$i] // ''; my $val2 = $arr2->[$i] // ''; my $val3 = $arr3->[$i] // ''; printf $fh_dest "%-20s%-20s%s\n", $val1, $val2, $val3; } print $fh_dest "\n"; } close ($fh_dest);
修复说明
- 按索引同步遍历:不再单独循环每个数组,而是根据索引同时获取三个数组的对应元素,确保同一行输出对应列内容。
- 处理数组长度差异:取三个数组中最长的长度作为循环次数,不存在的元素用空字符串填充,避免遗漏数据。
- 优化变量命名:将混淆的键名变量改为
$key,避免歧义;直接从数组取元素,解决未定义变量的问题。
内容的提问来源于stack exchange,提问作者suba suba
相关产品推荐
相关产品推荐

