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

データがハッシュに入れられる場所は 2 つあります

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 の 1 つの要素を参照します。ここには、基本的に同じ名前の 2 つの異なる変数があります。改善を探している場合は、値が uid であるため、スタイル的にハッシュを %uid と呼ぶ必要があります。

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" と、スクリプト実行時の午前 0 時からの分数である $START_MINUTE が作成されます。

スクリプトの後半で時刻が抽出され、午前 0 時からの分が同様の方法で検出されます (時間 * 60 + 分)

スクリプトのこの部分を「改善」するには、@mth 配列と sprintf 行の代わりに strftime を使用できます。

分の計算は、次のような名前のサブに移動できます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;

これは入力するのに時間がかかりますが、効率的には同じくらい効率的です。1 行に多数の操作を詰め込めるからといって、実行が速くなるわけではありません。ただし、私のものははるかに読みやすく、維持しやすいため、何時間もの作業を節約できます。たとえば、私の解析はlocaltimelocaltimeの Perldoc から直接取得されます。もしあなたが問題を見つけて、それが localtime の解析にあると思われるなら、私のコードを Perldoc とすぐに比較することができます.

実際、エラーがあります。ドキュメントを見localtimeて、私が持っているものと比較して$monthください$mday

Time::Pieceを使用する方がさらに良いでしょう。実際、Time::Pieceタイムスタンプの解析もよりクリーンになります。

したがって、コードが短くても理解しにくいだけでは良くなく、通常は実行効率が向上しないことを理解してください。

于 2013-06-24T14:14:06.760 に答える