NsshB has asked for the wisdom of the Perl Monks concerning the following question:

I am parsing a log file and trying to validate a value based on conditions within the log file using one of several hash tables. I am not getting any output and do not understand why.

Input file:
CMD, 2018/06/22, 14:21:44, ON, "GOBBLDY GOOK", PRI, "MORE GOBBLDY GOOK",
STAT, 2018/06,22, 14:21:44, A, ZELDA, "GOBBLDY GOOK",
STAT, 2018/06,22, 14:21:44, A, YAKOV, "GOBBLDY GOOK",
STAT, 2018/06,22, 14:21:44, U, XAVIER, "GOBBLDY GOOK",
STAT, 2018/06,22, 14:21:44, U, WALTER, "GOBBLDY GOOK",
STAT, 2018/06,22, 14:21:44, U, VICKY, "GOBBLDY GOOK",
CMD, 2018/06/22, 14:21:44, ON, "GOBBLDY GOOK", BU, "MORE GOBBLDY GOOK",
STAT, 2018/06,22, 14:21:44, A, ALISTAIR, "GOBBLDY GOOK",
STAT, 2018/06,22, 14:21:44, A, BARB, "GOBBLDY GOOK",
STAT, 2018/06,22, 14:21:44, U, CONNOR, "GOBBLDY GOOK",
STAT, 2018/06,22, 14:21:44, U, DENISE, "GOBBLDY GOOK",
STAT, 2018/06,22, 14:21:44, U, ERIN, "GOBBLDY GOOK",
CMD, 2018/06/22, 14:21:44, OFF, "GOBBLDY GOOK", PRI, "MORE GOBBLDY GOOK",
STAT, 2018/06,22, 14:21:44, U, ZELDA, "GOBBLDY GOOK",
STAT, 2018/06,22, 14:21:44, U, YAKOV, "GOBBLDY GOOK",
STAT, 2018/06,22, 14:21:44, A, XAVIER, "GOBBLDY GOOK",
STAT, 2018/06,22, 14:21:44, A, WALTER, "GOBBLDY GOOK",
STAT, 2018/06,22, 14:21:44, A, VICKY, "GOBBLDY GOOK",
CMD, 2018/06/22, 14:21:44, OFF, "GOBBLDY GOOK", BU, "MORE GOBBLDY GOOK",
STAT, 2018/06,22, 14:21:44, U, ALISTAIR, "GOBBLDY GOOK",
STAT, 2018/06,22, 14:21:44, U, BARB, "GOBBLDY GOOK",
STAT, 2018/06,22, 14:21:44, A, CONNOR, "GOBBLDY GOOK",
STAT, 2018/06,22, 14:21:44, A, DENISE, "GOBBLDY GOOK",
STAT, 2018/06,22, 14:21:44, A, ERIN, "GOBBLDY GOOK",

#! /usr/bin/perl my %dayTable0 = ( "ZELDA" => "U", "YAKOV" => "U", "XAVIER" => "A", "WALTER" => "A", "VICKY" => "A", ); my %dayTable1 = ( "ZELDA" => "A", "YAKOV" => "A", "XAVIER" => "U", "WALTER" => "U", "VICKY" => "U", ); my %nightTable0 = ( "ALISTAIR" => "U", "BARB" => "U", "CONNOR" => "A", "DENISE" => "A", "ERIN" => "A", ); my %nightTable1 = ( "ALISTAIR" => "A", "BARB" => "A", "CONNOR" => "U", "DENISE" => "U", "ERIN" => "U", ); open (FILE, my $file) or die "Can't open $file $!\n"; chomp (my @lines = <FILE>); foreach my $line (@lines) { my @line = split (/,/,$line); if ($line[0] =~ /CMD/) { my $state = $line[3]; my $unit = $line[5]; if ($state =~ /OFF/ && $unit =~ /PRI/) { %table = %dayTable0; } elsif ($state =~ /ON/ && $unit =~ /PRI/) { %table = %dayTable1; } elsif ($state =~ /OFF/ && $unit =~ /BU/) { %table = %nightTable0; } elsif ($state =~ /ON/ && $unit =~ /BU/) { %table = %nightTable1; } else { print "UNKNOWN STATE!! GO FIX SOMETHING!!!"; } } if ($line[0] =~ /STAT/) { my $name = $line[5]; my $status = $line[4]; my $value = $table{$name}; <p> Have tried several variants of above line. $table{ZELDA} gives me +the expected static response<\p> print "LOOKUP STATUS: $value\n"; } }

Replies are listed 'Best First'.
Re: Unable to extract value from hash table
by tybalt89 (Monsignor) on Jun 23, 2018 at 15:05 UTC

    Leading space!

    Change my @line = split (/,/,$line); to my @line = split (/, */,$line);

      Thanks for the help. My gut told me it was a simple fix but I just couldn't see it.

      Perhaps a slightly-safer split-regex might be: /\s*,\s*/ or something along those lines.

      This splits on “a comma, preceded and followed by zero-or-more whitespace characters.”   So the match will occur whether-or-not the comma is surrounded on either side by whitespace, and will “eat” both the comma and the whitespace.

      $ perl -e 'use Data::Dumper; my $a = "a, b , c,d"; my @b = split(/\s*, +\s*/, $a); print Data::Dumper->Dump([\@b], ['b']);' $b = [ 'a', 'b', 'c', 'd' ];
      but also note ...
      $ perl -e 'use Data::Dumper; my $a = " a, b , c,d "; my @b = split(/\s +*,\s*/, $a); print Data::Dumper->Dump([\@b], ['b']);' $b = [ ' a', 'b', 'c', 'd ' ];
      (Which is a valid and correct parse since the example string contains leading and trailing spaces, which split of course does not care about.)

      Therefore, an equally good possible strategy therefore would be to split on /,/ alone, then separately remove leading and/or trailing whitespace from each piece.   Or, remove any leading and/or trailing whitespace from the entire line before splitting it up as described.   If you do not care to install String::Util to get access to a trim() function, you can also use this Perl-foo to remove leading and trailing whitespace:  $str =~ s/^\s+|\s+$//g

Re: Unable to extract value from hash table
by Athanasius (Archbishop) on Jun 23, 2018 at 15:18 UTC

    Hello NsshB,

    tybalt89 beat me to it, but here’s the answer I was about to post, which expands a bit on the answer he’s given:

    If you output the value of $name like this:

    if ($line[0] =~ /STAT/) { my $name = $line[5]; print "name = >$name<\n"; my $status = $line[4];

    you will see that the first occurrence prints as name = > ZELDA<, which shows there is an extra space in the string. And since %table has no key named ' ZELDA', the table lookup fails.

    A simple way to fix this is to change this line:

    my @line = split (/,/,$line);

    to this:

    my @line = split (/\s*,\s*/,$line);

    which treats any whitespace as part of the delimiter.

    BTW, you really should begin every script with:

    use strict; use warnings;

    — and then you’ll need to declare %table before the loop:

    chomp (my @lines = <FILE>); my %table; foreach my $line (@lines) { ...

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: Unable to extract value from hash table
by jdporter (Paladin) on Jun 25, 2018 at 21:04 UTC

    What happens if any of those quoted fields contain any commas?

    Seems to me you'd be much better off using a CSV parsing module (like Text::CSV_XS) to parse this stuff.

    I reckon we are the only monastery ever to have a dungeon stuffed with 16,000 zombies.