Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

parsing and get the report

by perlthirst (Scribe)
on Dec 20, 2008 at 11:46 UTC ( #731749=perlquestion: print w/ replies, xml ) Need Help??
perlthirst has asked for the wisdom of the Perl Monks concerning the following question:


I am having one requirement.
my input format is like this.

month-date hh:mm:ss tid1 start trname tramount
month-date hh:mm:ss tid2 start trname tramount
month-date hh:mm:ss tid1 stop
month-date hh:mm:ss tid3 start trname tramount
month-date hh:mm:ss tid2 stop
month-date hh:mm:ss tid3 stop
month-date hh:mm:ss tid4 start trname tramount

where tid is transaction id, trname is transaction name and tramount is transaction amount.

I want the output - transaction id, transaction name, transaction amount and duration of the transaction ( diff between start time and end time).

One more in the report, if the transaction is started but not stopped, that also should get highlighted in the output

To do this I have done the coding, and it is working for me

Input:
12-20 12:10:06 12 start idbi 1000
12-20 12:11:23 16 start hdfc 2000
12-20 14:03:24 12 stop
12-20 14:45:53 18 start icici 2018
12-20 15:12:32 16 stop
12-20 15:45:60 18 stop
12-20 16:00:03 112 start universal 3400
Output:
Transaction id 12 name idbi Amount 1000 Duration 1:53:18
Transaction id 16 name hdfc Amount 2000 Duration 3:1:9
Transaction id 18 name icici Amount 2018 Duration 1:0:7
============================================
Transaction with id 112 is started but not yet stopped

My code is here:
$File = "input.txt"; open(FH,$File); while ( <FH>) { ## Chomp the read line. i.e removing \n available at the end chomp; ## taking time, transaction id, status, transaction name and amou +nt. if ( $_ =~ /([0-9]+\:[0-9]+\:[0-9]+) ([0-9]+) (\w+) (\w+) (\w+)/ ) +{ $time = $1; $tid = $2; $status = $3; $trname = $4; $tramount = $5; $hash{$2}->[0] = $status; $hash{$2}->[1] = $time; $hash{$2}->[2] = $trname; $hash{$2}->[3] = $tramount; } ## If the status is stop.. elsif ( $_ =~ /([0-9]+\:[0-9]+\:[0-9]+) ([0-9]+) (\w)/ ) { $status = $3; $hash{$2}->[0] = $status; $difftime = find_diff($hash{$2}->[1],$1); $hash{$2}->[1] = $difftime; print "Transaction id $2 name ".$hash{$2}->[2]." Amount ". $ha +sh{$2}->[3]." Duration ".$hash{$2}->[1]."\n"; # If the transaction is stopped initialising the values. $hash{$2}->[0] = 0; $hash{$2}->[1] = 0; $hash{$2}->[2] = 0; $hash{$2}->[3] = 0; } } print "============================================\n"; ## to print the transaction started but not yet stopped foreach $id ( keys %hash ) { if ( $hash{$id}->[0] =~ /start/i ) { print "Transaction with id $id is started but not yet stop +ped\n"; } } sub find_diff { ## Get the start time and end time and store that in a variable. my ( $begin, $end ) = @_; # Declaration of local variables. my ( $hour , $min, $sec , $hour1, $min1, $sec1, $tdiff); # split the start time which has a : as a seperator, and store hou +r, min # sec. ($hour, $min, $sec ) = split(/\:/,$begin); # Convert the start time into seconds. $stime = ( $hour *3600 ) + ($min *60) + $sec; # split the end time which has a : as a seperator, and store hour, + min # sec. ($hour1, $min1, $sec1 ) = split(/\:/,$end); # Convert the end time into seconds. $etime = ( $hour1 *3600 ) + ($min1 *60) + $sec1; # subtract the end time from start time. $diff = $etime - $stime; # conversion of seconds to hour, min and sec. $hour = int($diff/3600); $min1 = int($diff%3600); $min = int($min1/60); $sec = int($min1%60);# Form the hour min sec like hh:mm:ss $tdiff = $hour.":".$min.":".$sec; # return the output. return $tdiff; }

Kindly advice some efficient and short method for this.

Comment on parsing and get the report
Download Code
Re: parsing and get the report
by toolic (Chancellor) on Dec 20, 2008 at 13:06 UTC
    Trying to account for all the quirks of the calendar is very tricky business. That is why there are so many CPAN modules which will do this for you, Date::Calc, for example. You should seriously consider replacing your find_diff sub with something tried and tested from CPAN.

    use warnings; use strict;

    Check the success of open, use its 3-argument form and use lexical filehandles, $fh:

    open my $fh, '<', $File or die "can not open $File: $!"; while (<$fh>) { ... } close $fh;

    This:

    if ( $_ =~ /([0-9]+\:[0-9]+\:[0-9]+) ([0-9]+) (\w+) (\w+) (\w+)/ ){

    is more concisely written as this:

    if (/(\d+:\d+:\d+) (\d+) (\w+) (\w+) (\w+)/ ){

    Update: OK, I'm back in from shoveling snow. You should choose a better name for your hash data structure than %hash. I dont think you need all those extra variables, just stuff them into your hash right away.

    use strict; use warnings; my %hash; my $File = "input.txt"; open my $fh, '<', $File or die "can not open $File: $!"; while (<$fh>) { chomp; ## taking time, transaction id, status, transaction name and amoun +t. if (/(\d+:\d+:\d+) (\d+) (\w+) (\w+) (\w+)/ ){ $hash{$2} = [($3, $1, $4, $5)]; } ## If the status is stop.. elsif (/(\d+:\d+:\d+) (\d+) (\w)/ ) { $hash{$2}->[0] = $3; my $difftime = find_diff($hash{$2}->[1], $1); $hash{$2}->[1] = $difftime; print "Transaction id $2 name $hash{$2}->[2] Amount $hash{$2}- +>[3] Duration $hash{$2}->[1]\n"; # If the transaction is stopped initialising the values. delete $hash{$2}; } } close $fh; print "============================================\n"; ## to print the transaction started but not yet stopped for my $id ( keys %hash ) { if ( $hash{$id}->[0] =~ /start/i ) { print "Transaction with id $id is started but not yet stopped\ +n"; } }
Re: parsing and get the report
by Dhanasekar (Acolyte) on Dec 20, 2008 at 14:16 UTC
    # If the transaction is stopped initializing the values. $hash{$2}->[0] = 0; $hash{$2}->[1] = 0; $hash{$2}->[2] = 0; $hash{$2}->[3] = 0;
    Instead of initializing to 0, delete the hash like  delete ( $hash{$2} ) which could optimize the use of memory.
    Also instead of using  $hash{$2}->[1]  i.e., using Array in Hash use Hash of Hash which will be more readable !!
      Dear Dhanasekar, It is not quite fine always deleting and creating the same ,this dffer based on the situvation .
      Best Regards, S.Sabarinathan,
Re: parsing and get the report
by apl (Monsignor) on Dec 20, 2008 at 15:11 UTC
    Unless you had some other use for the intermediate variables, I'd replace
    $time = $1; $tid = $2; $status = $3; $trname = $4; $tramount = $5; $hash{$2}->[0] = $status; $hash{$2}->[1] = $time; $hash{$2}->[2] = $trname; $hash{$2}->[3] = $tramount;
    with
    $hash{$2}{status} = $3; $hash{$2}{time} = $1; $hash{$2}{trname} = $4; $hash{$2}{tramount} = $5;
    It's slightly shorter, and slightly more readable. (That is, it prevents you from asking 'What does subscript 2 stand for again?'.)
Re: parsing and get the report
by ig (Vicar) on Dec 20, 2008 at 15:31 UTC

    I would:

    • Use a hash of hashes, as Dhanasekar recommended
    • Use split rather than a RE to extract fields
    • Test for unexpected input

    Something like the following...

    my %transactions; ... my @fields = split(/\s+/); my %rec; $rec{$_} = shift(@fields) for ( qw(date time tid status trname tramoun +t) ); if ( $rec{status} eq "start" ) { $transactions{$rec{tid}} = \%rec; } elsif ( $rec{status} eq "stop" ) { if ( exists($transactions{$rec{tid}}) ) { # report transaction time and amount } else { warn "ERROR: stop without start: $_"; } } else { warn "ERROR: unrecognized status: $_"; }

    Update: and include the date in the transaction time calculation: think about what happens if the transaction starts late one day and stops early the following day.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://731749]
Approved by Perlbotics
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (10)
As of 2014-09-02 12:03 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite cookbook is:










    Results (22 votes), past polls