修复含引用错误的Hash文件并适配i-signal检索脚本
解决Perl脚本处理含自引用条目Hash文件的执行失败问题
我编写了一段Perl脚本,功能是读取my_hash_data.txt文件,检索值为“i-signal”的条目,并将其父键保存到i-signal-output.txt。脚本在测试Hash文件上运行正常,但处理正式大文件时,因为文件里存在'SignalTextTable' => $VAR1->{'VLAN_FAS'}{'NetworkPdus'}这类自引用错误条目,导致脚本执行失败,需要移除这些错误条目来适配原有脚本。
测试可用的Hash示例
$mein_hash = { 'CORRECT_1' => { 'Signalwert' => 'i-signal', 'Zeitstempel' => { 'stempel' => { 'Signalwert' => 'new-sig', } } }, 'Data' => { 'Email' => 'whatever@asdf.com', 'CORRECT_2' => { 'Signalwert' => 'i-signal', 'SignalTextTable' => 'asdf', }, 'Telefon' => '0123456789' }, 'Alter' => 30, 'Name' => 'Max Mustermann' };
含错误条目的Hash示例
$mein_hash = { 'CORRECT_1' => { 'Signalwert' => 'i-signal', 'Zeitstempel' => { 'stempel' => { 'Signalwert' => 'new-sig', 'SignalTextTable' => $VAR1->{'VLAN_FAS'}{'NetworkPdus'}, } } }, 'Data' => { 'Email' => 'whatever@asdf.com', 'CORRECT_2' => { 'Signalwert' => 'i-signal', 'SignalTextTable' => 'asdf', }, 'Telefon' => '0123456789' }, 'Alter' => 30, 'Name' => 'Max Mustermann' };
原有可正常运行的脚本
use strict; use warnings; use Data::Dumper; use File::Spec; # standard library chdir("U:\\tests"); # Searches a hash for a special keyword "i-signal". my %gefunden; sub finde_i_signal { my ($hash_ref, $parent_key) = @_; foreach my $key (keys %$hash_ref) { if (ref($hash_ref->{$key}) eq 'HASH') { finde_i_signal($hash_ref->{$key}, $key); } elsif ($hash_ref->{$key} eq 'i-signal') { $gefunden{$parent_key} = 1; } } } # Filename of the .txt file in the same folder my $datei_name = "mein_hash_data.txt"; # Open and read the .txt file if (open(my $datei_handle, '<', $datei_name)) { local $/; my $datei_inhalt = <$datei_handle>; close($datei_handle); # Remove the surrounding dollar signs and the variable name. $datei_inhalt =~ s/^\$mein_hash\s*=\s*//; # Convert the content into a hash reference my $datei_hash_ref = eval $datei_inhalt; die "Invalid format in the file $datei_name" if !$datei_hash_ref || ref($datei_hash_ref) ne 'HASH'; # Now call the function and pass the hash reference finde_i_signal($datei_hash_ref, undef); # Save found i-signals in "HASH_i-signal-output.txt open(my $file_handle, '>', 'HASH_i-signal-output.txt') or die "Kann die Datei nicht öffnen: $!"; foreach my $key (keys %gefunden) { print $file_handle "$key\n"; } close($file_handle) or die "Error closing the file: $!"; } else { die "The file $datei_name could not be opened: $!"; }
解决方案:移除自引用错误条目
问题根源是eval解析自引用代码时失败——$VAR1在当前上下文未定义。我们可以在解析前用正则表达式批量移除这类自引用条目:
在原有脚本的$datei_inhalt =~ s/^\$mein_hash\s*=\s*//;之后添加以下代码:
# 移除所有包含$VAR1->的自引用条目 $datei_inhalt =~ s/^\s*'[^']+'\s*=>\s*\$VAR1->\{[^}]+\}(?:\{[^}]+\})*,\s*//mg; # 处理可能遗留的末尾逗号(避免解析错误) $datei_inhalt =~ s/,\s*(\}|\])/$1/g;
修改后的完整脚本
use strict; use warnings; use Data::Dumper; use File::Spec; # standard library chdir("U:\\tests"); # Searches a hash for a special keyword "i-signal". my %gefunden; sub finde_i_signal { my ($hash_ref, $parent_key) = @_; foreach my $key (keys %$hash_ref) { if (ref($hash_ref->{$key}) eq 'HASH') { finde_i_signal($hash_ref->{$key}, $key); } elsif ($hash_ref->{$key} eq 'i-signal') { $gefunden{$parent_key} = 1; } } } # Filename of the .txt file in the same folder my $datei_name = "mein_hash_data.txt"; # Open and read the .txt file if (open(my $datei_handle, '<', $datei_name)) { local $/; my $datei_inhalt = <$datei_handle>; close($datei_handle); # Remove the surrounding dollar signs and the variable name. $datei_inhalt =~ s/^\$mein_hash\s*=\s*//; # 移除所有包含$VAR1->的自引用条目 $datei_inhalt =~ s/^\s*'[^']+'\s*=>\s*\$VAR1->\{[^}]+\}(?:\{[^}]+\})*,\s*//mg; # 处理可能遗留的末尾逗号(避免解析错误) $datei_inhalt =~ s/,\s*(\}|\])/$1/g; # Convert the content into a hash reference my $datei_hash_ref = eval $datei_inhalt; die "Invalid format in the file $datei_name" if !$datei_hash_ref || ref($datei_hash_ref) ne 'HASH'; # Now call the function and pass the hash reference finde_i_signal($datei_hash_ref, undef); # Save found i-signals in "HASH_i-signal-output.txt open(my $file_handle, '>', 'HASH_i-signal-output.txt') or die "Kann die Datei nicht öffnen: $!"; foreach my $key (keys %gefunden) { print $file_handle "$key\n"; } close($file_handle) or die "Error closing the file: $!"; } else { die "The file $datei_name could not be opened: $!"; }
说明
- 第一个正则表达式匹配并移除所有
'Key' => $VAR1->{'...'}{'...'},格式的自引用条目,mg修饰符确保跨多行匹配。 - 第二个正则表达式处理移除条目后可能出现的末尾逗号(比如哈希最后一个元素后的冗余逗号),避免
eval解析时语法错误。
内容的提问来源于stack exchange,提问作者Xandl
相关产品推荐
相关产品推荐

