Goku Goku - 3 months ago 12
Perl Question

Perl Output format

I'm reading a log file and grouping it based on the 'Program' name and inturn its ID.

LOG FILE

------------------------------------------
DEV: COM-1258
Program:Testing
Reviewer:Jackie
Description:New Entries
rev:r145201
------------------------------------------
QA: COM-9696
Program:Testing
Reviewer:Poikla
Description:Some random changes
rev:r112356
------------------------------------------
JIRA: COM-1234
Program:Development
Reviewer:John Wick
Description:Genral fix
rev:r345676
------------------------------------------
JIRA:COM-1234
Program:Development
Reviewer:None
Description:Updating Received
rev:r909276
------------------------------------------
JIRA: COM-6789
Program:Testing
Reviewer:Balise Mat
Description:Audited
rev:r876391
------------------------------------------
JIRA: COM-8585
Program:Testing
Reviewer:Gold frt
Description: yet to be reviewed
rev:r565639


The code I have,

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dumper;

$Data::Dumper::Sortkeys = 1;
$Data::Dumper::Terse = 1;

my $file = "log.txt";
open FH, $file or die "Couldn't open file: [$!]\n";

my $data = {};
my $hash = {};
while ( <FH> )
{
my $line = $_;
chomp $line;
if ( $line =~ m/(-){2,}/ )
{

my $program = $hash->{Program} || '';
my $jira = $hash->{JIRA} || $hash->{QA} || $hash->{DEV} ||
+'';
if ( $program && $jira )
{
push @{ $data->{ $program }{ $jira }}, $hash;
$hash = {};
}
}
else
{
if ( $line =~ m/:/ )
{
my ( $key, $value ) = split /:\s*/, $line;
$hash->{ $key } = $value;
}
elsif ( $line =~ m#/# && exists $hash->{Files} )
{
$hash->{Files} .= "\n$line";
}
}
}
print 'data = ' . Dumper( $data );

foreach my $prg ( sort keys %{ $data } )
{
print "===========================================================
+=\n";
print " PROGRAM : $prg
+ \n";
print "===========================================================
+=\n";

foreach my $jira ( sort keys %{ $data->{ $prg }})
{
print "******************\n";
print "JIRA ID : $jira\n";
print "******************\n";

foreach my $hash ( @{ $data->{ $prg }{ $jira }} )
{
foreach my $key ( keys %{ $hash })
{
# print the data except Program and JIRA
next if $key =~ m/(Program|JIRA|DEV|QA)/;
print " $key => $hash->{ $key }\n";
}
print "\n";
}
}
}


I have a requirement to print the output in the below format and currently unable to do so with my logic, any ideas would be really helpful.

PROGRAM: Development
Change IDs:
1.JIRA
a.COM-1234

PROGRAM: Testing
Change IDs:
1.JIRA
a.COM-6789
b.COM-8585
2.QA
a.COM-9696
3.DEV
a.COM-1258

Answer

I would write this

use strict;
use warnings 'all';

use List::Util 'uniq';

my $file = 'log.txt';
open my $fh, $file or die "Couldn't open file: [$!]\n";

my @data;
{
    my %item;

    while ( <$fh> ) {
        chomp;

        if ( eof or /\-{2,}/ ) {
            push @data, { %item } if keys %item;
            %item = ();
        }
        else {
            my ( $key, $value ) = split /\s*:\s*/;
            next unless $value;
            $item{$key} = $value;
            $item{jira} = $key if grep { $key eq $_ } qw/ JIRA DEV QA /;
        }
    }
}

my %data;
{
    for my $item ( @data ) {
        my ($prog, $jira) = @{$item}{qw/ Program jira /};
        push @{ $data{$prog}{$jira} }, $item->{$jira};
    }
}

for my $prog ( sort keys %data ) {

    printf "PROGRAM:   %s\n", $prog;
    print "Change IDs:\n";

    my $n = 1;
    for my $jira ( qw/ JIRA QA DEV / ) {

        next unless my $codes = $data{$prog}{$jira};

        printf "%d.%s\n", $n++, $jira;

        my $l = 'a';
        printf "    %s.%s\n", $l++, $_ for sort(uniq(@$codes));
    }

    print "\n";
}

output

PROGRAM:   Development
Change IDs:
1.JIRA
    a.COM-1234

PROGRAM:   Testing
Change IDs:
1.JIRA
    a.COM-6789
    b.COM-8585
2.QA
    a.COM-9696
3.DEV
    a.COM-1258