FAQ
Hi there,

I have the following problem:

I want to read a logfile in which every line follows this rule:
<value1>:<value2>:<value3>...

But the number of values differs. Sometimes a line has 2 values (the
minimum) and sometimes 3 or more values. Now I want to push these
values into a hash that follows that form:
$hash->{value1}->{value2}...

This is what I have so far:

sub readLog {
my $self = shift;
my $logfile = getFilename();

open LOG, "<$logfile";

foreach my $line (<LOG>) {
my @values = split /\:/, $line;
... # at this point I don't know what to do :(
}
}

Greetings
Dennis

Search Discussions

  • Shlomi Fish at Dec 1, 2010 at 9:39 am
    Hi Dennis,
    On Wednesday 01 December 2010 11:24:02 Dennis Jakobi wrote:
    Hi there,

    I have the following problem:

    I want to read a logfile in which every line follows this rule:
    <value1>:<value2>:<value3>...

    But the number of values differs. Sometimes a line has 2 values (the
    minimum) and sometimes 3 or more values. Now I want to push these
    values into a hash that follows that form:
    $hash->{value1}->{value2}...

    This is what I have so far:
    First a few comments on your code:

    sub readLog {
    my $self = shift;
    my $logfile = getFilename();
    Are you sure you want to:

    1. Use camelCase.

    2. Not do $self->get_filename().

    3. Call it "get_filename()" instead of "get_log_filename()"?
    open LOG, "<$logfile";
    Use three-args-open, lexical filehandles, etc:

    http://perl-begin.org/tutorials/bad-elements/#open-function-style
    foreach my $line (<LOG>) {
    «while (my $line = <$log>)» would be more preferable here because it will
    consume less memory:

    http://perl-begin.org/tutorials/bad-elements/#foreach-lines
    my @values = split /\:/, $line;
    split /:/ will work just as well, as ":" is not a special character.
    ... # at this point I don't know what to do :(
    OK, here's what you can do (untested):

    [code]
    my $hash_ref = \%hash;

    foreach my $val (@values[0 .. $#values-2])
    {
    $hash_ref = ($hash_ref->{$val} ||= {});
    }

    $hash_ref->{$values[-2]} = $values[-1];
    [/code]

    I did not deal with some edge cases, but hopefully it will be OK.

    Regards,

    Shlomi Fish

    --
    -----------------------------------------------------------------
    Shlomi Fish http://www.shlomifish.org/
    Funny Anti-Terrorism Story - http://shlom.in/enemy

    <rindolf> She's a hot chick. But she smokes.
    <go|dfish> She can smoke as long as she's smokin'.

    Please reply to list if it's a mailing list post - http://shlom.in/reply .
  • Rob Coops at Dec 1, 2010 at 9:42 am

    On Wed, Dec 1, 2010 at 10:24 AM, Dennis Jakobi wrote:

    Hi there,

    I have the following problem:

    I want to read a logfile in which every line follows this rule:
    <value1>:<value2>:<value3>...

    But the number of values differs. Sometimes a line has 2 values (the
    minimum) and sometimes 3 or more values. Now I want to push these
    values into a hash that follows that form:
    $hash->{value1}->{value2}...

    This is what I have so far:

    sub readLog {
    my $self = shift;
    my $logfile = getFilename();

    open LOG, "<$logfile";

    foreach my $line (<LOG>) {
    my @values = split /\:/, $line;
    ... # at this point I don't know what to do :(
    }
    }

    Greetings
    Dennis

    --
    To unsubscribe, e-mail: beginners-unsubscribe@perl.org
    For additional commands, e-mail: beginners-help@perl.org
    http://learn.perl.org/

    Hi Dennis

    I know a weird question that you likely already thought about but still why
    are you not using a combination of array and hash?

    $hash->{value1} = [ value2, value3, value4, ... ]

    It would save you a lot of headaches in looping over all values that are on
    that one line because how are you going to easily handle a situation where
    you have a hash of hashes with an undefined depth without having to jump to
    a lot of difficult hoops to make it work properly?

    Regards,

    Rob
  • Dennis Jakobi at Dec 1, 2010 at 10:56 am
    Thanks for the codingstyle tips, Shlomi. I instantly changed that =)

    @Rob: The structure of my data is like

    category_a->index_a->value_a
    category_a->index_b->value_b
    category_a->category_b->index_a->value_a

    So sometimes I have a category in a category, sometimes it is just a
    value in a category. I think in my case it is better to have a
    hash-monster like that. I feel more comfortable with this style of
    datastructure. But if anyone has a better idea to handle this, I'd be
    glad to hear =)

    Now to the code itself: I forgot to mention that its not actually a
    hash, its an object. Sorry for that mistake. That might be the reason
    why the code Shlomi gave to me doesn't work as intented. The $hash_ref
    has some values in it, but not in the correct structure and not every
    line from the file read finds its way to the hash_ref. Now thats what
    I got so far:

    [code]
    sub read_log {
    my $self = shift;
    my $filename = get_filename();
    print "\n$filename\n";

    open my $log, "<", $filename or die "Error opening file: $!";

    while (my $line = <$log>) {
    chomp $line;
    my @values = split /:/, $line;
    my $hash_ref = $self;
    foreach my $val (@values[0 .. $#values-2])
    {
    $hash_ref = ($self->{$val} ||= {});
    }

    $hash_ref->{$values[-2]} = $values[-1];
    }

    print Dumper $self;
    }
    [/code]


    Greetings
    Dennis
    2010/12/1 Rob Coops <rcoops@gmail.com>:
    On Wed, Dec 1, 2010 at 10:24 AM, Dennis Jakobi wrote:

    Hi there,

    I have the following problem:

    I want to read a logfile in which every line follows this rule:
    <value1>:<value2>:<value3>...

    But the number of values differs. Sometimes a line has 2 values (the
    minimum) and sometimes 3 or more values. Now I want to push these
    values into a hash that follows that form:
    $hash->{value1}->{value2}...

    This is what I have so far:

    sub readLog {
    my $self = shift;
    my $logfile = getFilename();

    open LOG, "<$logfile";

    foreach my $line (<LOG>) {
    my @values = split /\:/, $line;
    ... # at this point I don't know what to do :(
    }
    }

    Greetings
    Dennis

    --
    To unsubscribe, e-mail: beginners-unsubscribe@perl.org
    For additional commands, e-mail: beginners-help@perl.org
    http://learn.perl.org/
    Hi Dennis
    I know a weird question that you likely already thought about but still why
    are you not using a combination of array and hash?
    $hash->{value1} = [ value2, value3, value4, ... ]
    It would save you a lot of headaches in looping over all values that are on
    that one line because how are you going to easily handle a situation where
    you have a hash of hashes with an undefined depth without having to jump to
    a lot of difficult hoops to make it work properly?
    Regards,
    Rob

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupbeginners @
categoriesperl
postedDec 1, '10 at 9:24a
activeDec 1, '10 at 10:56a
posts4
users3
websiteperl.org

People

Translate

site design / logo © 2021 Grokbase