我试图理解以下脚本的逻辑,特别是在哈希和时间扫描中存储内容方面,还有任何关于改进的建议,以使其更短。
#!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
答案 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
也可以使解析时间戳更加清晰。
所以,请理解更短的代码并不是更好,如果它更难理解,并且它通常不会更有效地执行。