2015-06-23 37 views
1

我正在尝试使用来自目录中所有文本文件的单词来填充数组的散列。单词用作键,文件名用作与键相关联的标量值。在Perl中填充和搜索数组的散列?

我正在使用数组的散列,因为一个单词可能很容易在另一个文本文件中重复。我想填写散列表;那么我想通过关键词搜索来确定哪些文件包含一些给定的关键字。

我的代码的摘录:

# Search term(s). 
my @search_terms = ("random", "searches"); 

opendir(DIR, $directory) or die $!; 
@files = grep(/\.txt$/, readdir(DIR)) or die("you idiot"); 

# Create a hash table to store the words as keys and the file name. 
my %hash; 

# Go through the files, grab the words, and create hash table. 
foreach my $file(@files) { 
    open(FILE,"<$file") or die $!; 
    while(<FILE>){ 
     chomp; 
     my @words = split(' '); 
     # Store the key, value pairs for each file. 
     # Key is the word. 
     # Value is the file name. 
     foreach my $word(@words) { 
      push @{$hash{$word}}, $file; 
     } 
    } 
    close(FILE); 
} 

# Go through each search term. 
foreach my $match(@search_terms) { 
    # If a key exists in the hash table, then we have a matched result. 
    if($hash{$match}) { 
     # Print the file name (scalar value for word key). 
     print "$hash{$match} matched."; 
     print "\n"; 
    } 
} 

看来,也许我没有正确填写我的哈希(或者我只是不知道如何打印数组的哈希值)。另外,我的匹配对于文件不正确。任何帮助,我做错了什么将不胜感激!谢谢!

回答

1

你缺少的事情是,确实没有任何这样的东西在Perl阵列的哈希值。或一组哈希值。数组和哈希都只能包含一个值。

他们的方式perl的 '不' 多维通过引用:

my %hash; 
push (@{$hash{'fish'}}, "trout"); 

foreach my $key (keys %hash) { 
    print "$key $hash{$key}\n"; 
} 

这将打印(类似):

fish ARRAY(0x2d6ed4) 

这是因为在$hash{$key}单个值是对该数组的引用。然后您需要取消引用才能访问。

E.g.

print join ("\n", @{$hash{$key}}); 

例如。

Data::Dumper可以帮助你了解这是怎么回事:

my %hash; 
push (@{$hash{'fish'}}, "trout"); 

print Dumper \%hash; 

打印:

$VAR1 = { 
      'fish' => [ 
         'trout' 
        ] 
     }; 

要回答你原来的问题 - 稍微改变你的foreach循环:

foreach my $match (@search_terms) { 
    # If a key exists in the hash table, then we have a matched result. 
    if($hash{$match}) { 
     # Print the file name (scalar value for word key). 
     # $hash{$match} is an array reference, so we need to de-reference: 
     my @matching_files = @{$hash{$match}}; 
     print "$match found in:\n"; 
     print join ("\n", @matching_files),"\n"; 
    } 
} 

(为了清晰起见,我已经制作了一些比详细的更详细的信息 - 你可以减少i尽管如此)。

我也将提供一定的辅助建议:

  • 打开strictwarnings。它们对编写好的代码非常重要。
  • 不要使用那样的open。尝试改为:

    open (my $file, "<", $filename) or die $!; 
    while (<$file>) { ... } 
    
  • 我喜欢globreaddirgrep,因为你做了该方法的陷阱之一是,所有的open旨意失败,除非$directory也是当前的工作目录。 (你需要添加一个路径到文件名)。 :

    foreach my $filename (glob "$directory/*.txt") { ... } 
    
  • split(' ');是好的,但它一样split;。选择你觉得最可读的。

  • 你实际上并不需要做my @words = split;你可以只是做foreach my $word (split) { ...

0

你靠近,只需要在每个哈希键展开疗法rray

# Go through each search term. 
foreach my $match(@search_terms) { 
    # If a key exists in the hash table, then we have a matched result. 
    if($hash{$match}) { 
     # Print the file name (scalar value for word key). 
     print "$hash{$match} matched in file(s) "; 
     foreach my $elem (@{"$hash{$match}}) { 
      print "$elem : " 
     } 
     print "\n"; 
    } 
}