0

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

#!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
4

2 回答 2

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

很难说改进哈希的使用,因为在显示的程序段的上下文之外不清楚它们的用途

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

于 2013-06-24T09:17:49.937 回答
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也会使解析时间戳更加清晰。

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

于 2013-06-24T14:14:06.760 回答