【问题标题】:Parse text file and store delimited fields in hash table (Perl)解析文本文件并将分隔字段存储在哈希表中(Perl)
【发布时间】:2018-12-29 05:37:36
【问题描述】:

我对 Perl 还很陌生,如果我在这里遗漏了一些非常简单的东西,我深表歉意。

我有一个格式如下的文件:

TGName: name1             
----------------------------------------------------------------------------
 setting1                                          value1 
 setting2                                          value2
 setting3                                          value3   
 setting4                                          value4
 setting5                                          value5

 ...
 ...

TGName: name47             
----------------------------------------------------------------------------
 setting1                                          value1 
 setting2                                          value2
 setting3                                          value3

 ...
----------------------------------------------------------------------------
SGName: name1             
----------------------------------------------------------------------------
 ...

需要与类似的文本文件进行比较(即格式化乱序)。我的想法是我可以将文本文件的每个“块”存储在哈希中,所以上面看起来像:

my %TGName:name1= (
    setting1 => 'value1',
    setting2 => 'value2',
    setting3 => 'value3',
    setting4 => 'value4',
);

以此类推,然后我可以将两个文件中具有相同名称的每个哈希相互比较。

我现在面临的问题是将以 TGName、SGName 等开头的每一行读入散列,并将设置和值作为键/值对。

This 问题的编辑与我在搜索时找到的最接近,但遗憾的是在编辑原始问题后没有人回答。

任何见解将不胜感激!

编辑:这是一个有点相似(且更简单)的项目的一些代码,其中每一行都是唯一的并且没有分成组。在这里,输出列出了两个文件共有的行,仅在第一个文件中找到的行,以及仅在第二个文件中找到的行:

use strict;
use warnings;
use List::Compare;

# create log.txt for writing
my $log = 'log.txt';

# create $f1 string and read in file1
open (my $f1, "<", "file1.txt") or die $!;

# create $f2 string and read in file2
open (my $f2, "<", "file2.txt") or die $!;

# initialize array and populate with the contents of $f1
my @content_f1=<$f1>;

# initialize array and populate with the contents of $f2
my @content_f2=<$f2>;

# create comparison string
my $lc = List::Compare->new(\@content_f1, \@content_f2);    

# initialize array showing commonalities of file 1 and file 2  
# and populate with the contents of get_intersection() 
my @intersection = $lc->get_intersection;

# initialize array showing elements unique to new config  
# and populate with the contents of get_unique() 
my @firstonly = $lc->get_unique;

# initialize array showing elements unique to golden config
# and populate with the contents of get_complement() 
my @secondonly = $lc->get_complement;

# create $out string to write contents into log
open(my $out, '>', $log) or die "Cannot open file '$log' for writing: $!";

# write the contents of the intersection and unique arrays to log.txt
print $out "Common Items:\n"."@intersection"."\n";
print $out "Items Only in file 1 \n"."@firstonly"."\n";
print $out "Items Only in file 2:\n"."@secondonly"."\n";

close $out;
close $f1;
close $f2;

理想情况下,我希望在这里得到相同类型的输出,除了将文本文件与文本文件进行比较,而是将 %file1_hash_name1 与 %file2_hash_name1 进行比较(例如:两个散列共有的项目、仅在第一个散列中找到的项目、项目仅在第二个哈希中找到)。

【问题讨论】:

  • “需要与类似的文本文件进行比较” 好的,但您到底想要什么结果?只是一个文件中而不是另一个文件中的记录列表?如果顺序很重要,请记住散列是无序的。你的文件有多大?
  • 为了清晰起见,在我之前使用的一些代码中进行了编辑;希望这会有所帮助。文件是约 20,000 行文本。如果哈希是无序的,有没有更好的方法来存储它们以进行比较?

标签: perl file parsing hash hashmap


【解决方案1】:

在此示例中,我使用 Test::Deep 中的 eq_deeply 函数来测试两个文件之间的相等性。

如果您还要查找一个文件中的内容而另一个文件中没有的内容,则可以使用 List::Compare 函数。

#!/usr/bin/perl
use strict;
use warnings;
use Test::Deep::NoTest 'eq_deeply';
use List::Compare;

open my $fh, '<', \<<EOF;
TGName: name1
----------------------------------------------------------------------------
 setting1                                          value1 
 setting2                                          value2
 setting3                                          value3   
 setting4                                          value4
 setting5                                          value5


TGName: name47
----------------------------------------------------------------------------
 setting1                                          value1 
 setting2                                          value2
 setting3                                          value3

----------------------------------------------------------------------------
SGName: name1
EOF

my %data1;
my $key1;

while (<$fh>) {
    if (/^([A-Z]{2}Name: name\d+)/) {
        $key1 = $1;
    }
    elsif (/^[-\s]+$/) {
        next;
    }
    else {
        my ($setting, $val) = split;    
        $data1{$key1}{$setting} = $val;
    }
}

open my $fh2, '<', \<<EOF;
TGName: name1
----------------------------------------------------------------------------
 setting1                                          value1 
 setting2                                          value2
 setting3                                          value3   
 setting4                                          value4
 setting55                                          value5


TGName: name47
----------------------------------------------------------------------------
 setting1                                          value1 
 setting2                                          value2
 setting3                                          value3

----------------------------------------------------------------------------
SGName: name11
EOF

my %data2;
my $key2;

while (<$fh2>) {
    if (/^([A-Z]{2}Name: name\d+)/) {
        $key2 = $1;
    }
    elsif (/^(?:-+|\s+)$/) {
        next;
    }
    else {
        my ($setting, $val) = split;    
        $data2{$key2}{$setting} = $val;
    }
}

my $lc = List::Compare->new([keys %data1], [keys %data2]);
my @intersection = $lc->get_intersection;

for my $key (@intersection) {
    if (eq_deeply($data1{$key}, $data2{$key})) {
        print "key $key has the same hash for both files\n";    
    }
    else {
        print "key $key has different hashes\n";    
    }
}

输出是:

key TGName: name1 has different hashes
key TGName: name47 has the same hash for both files

我自己没有使用过eq_deeply函数,但我相信它会给你你需要的结果。

【讨论】:

  • 非常感谢!我更希望输出是内容的比较以及它们之间的差异,但是您解析文本并将其存储在哈希中的方式正是我所坚持的。
  • @Sameer: “我更希望输出是对内容及其差异的比较”在你的问题中。即使在我问“你到底想要什么结果?”之后,你也只提供了一些旧代码。
猜你喜欢
  • 2013-06-14
  • 2013-03-06
  • 2012-12-22
  • 1970-01-01
  • 2019-10-22
  • 1970-01-01
  • 1970-01-01
  • 2014-12-23
  • 2021-02-27
相关资源
最近更新 更多