在Perl中,如何将数组作为值存储在哈希中?

时间:2017-05-18 13:46:18

标签: regex perl hashtable

我不知道您是否被允许提出有关学校作业的问题。我只是想了解我应该做什么,而不是为我做这件事。也许我错过了一些如此简单的东西,它就在我面前,但无论如何它是基于一个较旧的任务,但我错过了这个课程,我现在遇到了一堵墙,问题是我和我一样。我试图将数组推入哈希表。使用这样的东西;

push @{$hash_table{$hash_key}}, $port

并在存储它们时计算端口,然后打印哈希的内容

while ( ($key , $value) = each ( %hash ) ) {
    print “$key scanned @{$value}” 
}

如果我想对结果进行排序,我会使用

< foreach $key ( keys ( %hash ) ) {
}

我当前的代码是这样的,搜索/ iNext-DROP /的字符串 使用提供的日志文件。我不能为我的生活找到添加上面代码的正确位置

use warnings;
my $LogRecord; 
my $LogRecordCount;
open LOGFILE, "sample.log.txt" or die "couldn't open sample.log.txt";
while ($LogRecord = <LOGFILE>) {
if  ($LogRecord =~ /INext-DROP/)    { 
    $LogRecordCount ++;
    $LogRecord =~ /(SRC=[0-9\.]* ).*(SPT=[0-9\.]* )/;
    $source=$1;
    $sport=$2;
print "$source$sport"; 
print substr( $LogRecord , 0 , $ARGV[1] ) , "\n"  if $ARGV[1];
 }
}
print "The file contained $LogRecordCount records" if $ARGV[1];
close LOGFILE;

这是带有评论的旧代码的图片; Old Code -- not much has changed since I keep going back after it doesn't work

1 个答案:

答案 0 :(得分:3)

你似乎遇到问题的是,你不确定捕获端口的位置和哈希更新。

正在发生的事情是您的while循环一次迭代文件一行,并将$LogRecord =~行正在捕获模式的值捕获到$1和{{1} }。

然后$2是您可以使用$2添加到哈希的内容。

然而,有一些事情我改变了风格,比如使用词法文件句柄,因为它的风格更好。

push

这是你的哈希。

但是当谈到输出时:

#!/usr/bin/env perl
use warnings;
use strict; 

#because it makes debugging easier. 
use Data::Dumper;

my $LogRecordCount;

#declare some hashes; 
my %ports_from; 
my %ips_that_used; 

open my $logfile, "sample.log.txt" or die "couldn't open sample.log.txt";
while (my $line = <$logfile>) {
    #matches 'current line' - skips stuff that doesn't match. 
    next unless $line =~ /INext-DROP/; 
    #increment count. 
    $LogRecordCount++;

    my ( $source, $src_port ) = $line =~ m/SRC=([0-9\.]+).*SPT=([0-9]+)/;  
    print "$source$sport"; 

    #not sure what this is doing, so I have left it in. 
    print substr( $line , 0 , $ARGV[1] ) , "\n"  if $ARGV[1];

    push @{$ports_from{$source}}, $src_port; 
    push @{$ips_that_used{$src_port}}, $source; 
 }
print "The file contained $LogRecordCount records" if $ARGV[1];
close $logfile;

print Dumper \%ports_from;
print Dumper \%ips_that_used; 

如果您想对它们进行排序,则必须使用foreach my $ip ( keys %ports_from ) { print "$ip: ", join ( " ", @{$ports_from{$ip}}) ,"\n" } 执行此操作。

现在sort是一个非常聪明的功能,但默认情况下会按字母数字排序。那就是......当涉及到IP地址或端口号时,实际上并不是那么有用,因为你可能想要用数字来对它们进行排序。简单的答案是sort并使用Sort::Naturally

然而 - nsort接受一个函数(默认为sort),它根据相对位置返回-1,0,1。

因此,按IP排序可能如下所示:

cmp

然后你可以:

sub by_ip { 
   my @a = split /\./, $a;
   my @b = split /\./, $b; 
   foreach my $octet ( @a ) { 
      my $comparison = $octet <=> shift ( @b ); 
      return $comparison if $comparison; 
   }
   return 0;
}

给你:

foreach my $ip ( sort by_ip keys %ports_from ) { 
   print "$ip: ", join ( " ", sort { $a <=> $b } @{$ports_from{$ip}}),"\n";
}

考虑到存在重复项的IP到端口映射,仅使用散列哈希而不是数组散列来计算端口频率可能更好。

24.64.208.134 : 24128  24128  24128 
71.228.199.109 : 37091 
72.197.8.56 : 9258 
75.117.31.43 : 3122 
99.248.20.48 : 48725 
207.68.178.56 : 80 

然后:

$count_ports_from{$source}{$src_port}++; 

给你类似的东西:

foreach my $ip ( sort by_ip keys %count_ports_from ) {
   print "$ip: ";
   foreach my $port_num ( sort { $count_ports_from{$a} <=> $count_ports_from{$b} } 
       keys %{ $count_ports_from{$ip} } )
   {
      print "\t $port_num : $count_ports_from{$ip}{$port_num}\n";
   }
}