脚本中的哈希逻辑

时间:2013-06-24 06:31:09

标签: perl hash

我试图理解以下脚本的逻辑,特别是在哈希和时间扫描中存储内容方面,还有任何关于改进的建议,以使其更短。

#!perl
use strict;
use warnings;


my $A = 60; # minutes
my @mth = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
my @f = localtime();
my $TODAY = sprintf "%02d/%s/%4d",$f[3],$mth[$f[4]],$f[5]+1900; 
my $START_MINUTE = $f[2]*60+$f[1] - $MAX_AGE;

##

my %users;
my %conn;

while (<DATA>) { 
 if( /\bAT\b/ ) {
  my( $conn, $uid ) = /conn=(\d+).*uid=(.*?),/;
    $conn{$conn} = $uid;
  }
  if( /ABB/ ) {
    my ($timestamp, $conn) = /\[(.*?)\] conn=(\d+)/;


    my ($date,$h,$m,undef) = split ':',$timestamp,4;
    next unless ($date eq $TODAY);
    my $minutes = $h*60 + $m;




    if ($minutes >= $START_MINUTE){
      my $uid = $conn{$conn}; 
      ++$users{$uid};
    }
  }
}


for my $uid (keys %users) {
  my $count = $users{$uid};
  print "$count\n" if  $count > 6;
}

_DATA_

[04/Jun/2013:13:06:13 -0600] conn=13570 op=14 msgId=13 - AT dn="conn=ad1222,o=xyz.com" method=128 version=3
[04/Jun/2013:15:06:13 -0600] conn=13570 op=14 msgId=15 - RESULT  ABB

2 个答案:

答案 0 :(得分:1)

有两个地方将数据放入哈希

my( $conn, $uid ) = /conn=(\d+).*uid=(.*?),/;
    $conn{$conn} = $uid;
  }

这很简单,正则表达式提取$ uid和$ conn并设置一个哈希条目,其中$ conn作为键,$ uid作为值。在本声明中

$conn{$conn}
^^^^^^     ^ this is a hash
      ^^^^^  this is a completely different scalar

总的来说,表达式$conn{$conn}是指带有标量键$ conn的散列%conn的单个元素。这里有两个不同的变量,名称基本相同! 如果你正在寻找改进,风格上哈希应该被称为%uid,因为它的值是uids

if ($minutes >= $START_MINUTE){
      my $uid = $conn{$conn}; 
      ++$users{$uid};

这是一个更“疯狂的perl”的东西,虽然它确实很直接,并且在代码中被广泛使用。它所做的就是增加密钥$ uid的哈希条目。如果$ user {$ uid}没有条目,则语句会自动生成并将值设置为1

更新以讨论“时间扫描”

my $A = 60; # minutes
my @mth = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
my @f = localtime();
my $TODAY = sprintf "%02d/%s/%4d",$f[3],$mth[$f[4]],$f[5]+1900; 
my $START_MINUTE = $f[2]*60+$f[1] - $MAX_AGE;

这使得“$ TODAY”是今天的日期,其格式与文件中的日期相匹配,$ START_MINUTE是自脚本运行时午夜以来的分钟数

稍后在脚本中提取一天中的时间,并以类似的方式找到午夜以来的分钟(小时* 60 +分钟)

要“改进”脚本strftime的这一部分可以用来代替@mth数组和sprintf行

分钟的计算可以移动到类似sub minutes_since_midnight

的子目录

在改进哈希的使用方面有点难以说明,因为目前尚不清楚它们在所显示的程序段的上下文中的用途是什么

希望或多或少地回答你的问题!!

答案 1 :(得分:0)

  

改进的任何建议使其更短

您不希望缩短来改进它。您需要使其更容易理解,以便改进它。您已经在理解逻辑方面遇到了问题,缩短逻辑不会对此有所帮助。

我们来看看:

my $A = 60; # minutes
my @mth = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
my @f = localtime();
my $TODAY = sprintf "%02d/%s/%4d",$f[3],$mth[$f[4]],$f[5]+1900; 
my $START_MINUTE = $f[2]*60+$f[1] - $MAX_AGE;

我可以通过逻辑并尝试弄明白,但更有可能的是,我将对原作者做出相同的逻辑假设。相反,我们可以通过使用好的变量名称和扩展逻辑来提高可读性:

my @month_list = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
my ( $sec, $min, $hour, $month, $mday, $year ) = localtime;  #Whoops!
my $full_year += 1900;
my $text_month = $month_list[$month];
my $today = sprintf "%02d/%s/%4d", $mday, $text_month, $full_year;

输入时间越长,效率也越高,效率也越高。仅仅因为你可以在一行上填充一堆操作就不会让它执行起来更快。但是,我的阅读更容易,更容易维护,这将节省你很多小时的工作。例如,我localtime的解析直接来自localtime上的Perldoc。如果您发现问题,并且您认为这可能是由于我解析了本地时间,您可以快速将我的代码与Perldoc进行比较。

事实上,有一个错误。看一下localtime文档并将其与我的文档进行比较,您会看到我已将$month$mday混为一谈。

更好的方法是使用Time::Piece。实际上,Time::Piece也可以使解析时间戳更加清晰。

所以,请理解更短的代码并不是更好,如果它更难理解,并且它通常不会更有效地执行。