Here's the scenario simplified. Data is stored in a (rather unorderly) fashion like so, but with lot more data fields than what I'm using here:
name:pete¦favcolor:blue¦uniqueid:567¦age:20
name:ruth¦favcolor:red¦uniqueid:688¦age:50
name:joe¦favcolor:blue¦uniqueid:99¦age:25
Usually, these records are sorted and printed by their unique id. Piece of cake. But now I need it to read from the data file and print like so:
red
ruth is 50
blue
pete is 20
joe is 25
doing a foreach by, say, the favcolor field.
Hope that makes sense.
First right answer gets a free Photoshop tutorial.
open DATA, "data.txt";
my @a = <DATA>;
close DATA;
my ($l, %stuff, %index);
foreach $l (@a) {
chomp $l;
my (%data) = split(/[¦:]/, $l);
print Dumper(\%data) ."\n\n";
$stuff{$data{'uniqueid'}} = \%data;
foreach (keys %data) {
my $ref = $index{$_}¦¦[];
my @t = @$ref;
push(@t,$data{$_});
$index{$_} = \@t;
}
}
print Dumper(\%stuff) ."\n\n";
print Dumper(\%index) ."\n\n";
# nice little structure can now be manipulated. eg.
my $color;
my $colref = $index{'favcolor'};
foreach $color (@$colref) {
print "\nColor $color\n";
foreach (values %stuff) {
my %p = %$_;
print "\t$p{'name'} is $p{'age'}\n" if $p{'favcolor'} eq $color;
}
}[/perl]
Remember the ¦ caveat ... in the split and ¦¦ - delete and retype to make work.
Probably a few performance enhancements that could be added in ... lots of looping in loops ;) If there are a huge number of vals, then the index could be extended to be a hash of hashes, eg.
favcolor => red => (323,44,32)
favcolor => blue => (3,23)
etc.
OK .. erm back to my work again.
Originally, this was called as an SSI, with the db to be used as the query:
$query = $ENV{QUERY_STRING};
print "Content-Type: text/html\n\n";
open (LOGFILE,"<$query\.db");
@log=<LOGFILE>;
close (LOGFILE);
print "<TABLE BORDER=\"0\" cellpadding=\"0\" cellspacing=\"4\" width=\"100%\">\n"; foreach $line (@log) {
@fieldsa = split(/\¦/, $line);
foreach $ize (@fieldsa) {
@izetomb = split(/\:/, $ize);
$ahash{$izetomb[0]} = $izetomb[1];
}
print "<tr><td>$ahash{'name'} $ahash{'favcolor'}</td></tr>\n";
... and whatever else. Would this (your snippet) work as an SSI with an html embedded query calling the logfile to be parsed?
I know. idiotgirl.
Also the dereferencing and referencing of vars could be done in fewer lines... but I think its confusing enough already.
[perl]#!perl -w
use Data::Dumper;
use strict;
open DATA, "data.txt";
my @a = <DATA>;
close DATA;
my ($l, %stuff, %index);
foreach $l (@a) {
chomp $l;
my (%data) = split(/[¦:]/, $l);
print Dumper(\%data) ."\n\n";
$stuff{$data{'uniqueid'}} = \%data;
foreach (keys %data) {
my $ref1 = $index{$_}¦¦+{};
my %t = %$ref1;
my $ref2 = $t{$data{$_}}¦¦[];
my @t = @$ref2;
push(@t,$data{'uniqueid'});
$t{$data{$_}} = \@t;
$index{$_} = \%t;
}
}
print Dumper(\%stuff) ."\n\n";
print Dumper(\%index) ."\n\n";
# nice little structure can now be manipulated. eg.
my $color;
my $colref = $index{'favcolor'};
my %colors = %$colref;
foreach $color (keys %colors) {
my $t = $colors{$color};
my @t = @$t;
print "\nColor $color\n";
foreach (@t) {
my $r = $stuff{$_};
my %p = %$r;
print "\t$p{'name'} is $p{'age'}\n";
}
}[/perl]
I tested this simple - using my test lines as data.txt, taking out the Data::Dumper, strict, and going vanilla.
I think the initial:
my (%data) = split(/[¦:]/, $line);
is causing errors.
I ran it both ways - with and without Data::Dumper, and I kept getting an error returned where the split was. I did change to pipes.
open DATA, "data.txt";
my @a = <DATA>;
close DATA;
my ($line, %stuff, %index);
foreach $line (@a) {
chomp $line;
my (%data) = split(/[¦:]/, $line);
$stuff{$data{'uniqueid'}} = \%data;
foreach (keys %data) {
my $ref1 = $index{$_}¦¦+{};
my %t = %$ref1;
my $ref2 = $t{$data{$_}}¦¦[];
my @t = @$ref2;
push(@t,$data{'uniqueid'});
$t{$data{$_}} = \@t;
$index{$_} = \%t;
}
}my $color;
my $colref = $index{'favcolor'};
my %colors = %$colref;
foreach $color (keys %colors) {
my $t = $colors{$color};
my @t = @$t;
print "\nColor $color\n";
foreach (@t) {
my $r = $stuff{$_};
my %p = %$r;
print "\t$p{'name'} is $p{'age'}\n";
}
}
I would reccommed using a loop like:
whie (<DATA>) {
# do stuff...
}
to walk through your file so you don't have to slurp the entire file into memory at the beginning.
You may also want to check the result of your call to "open"
open DATA, "data.txt" or die "cannot open data.txt. $!";
or something.