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

Hey,

Alrighty. Say we have:
my %inst = ( "unimp" => "\e[31munimp\e[0m", "be" => "\e[31mbe\e[0m", "bne" => "\e[31mbne\e[0m", "ba" => "\e[31mba\e[0m", "bl" => "\e[31mbl\e[0m", "call" => "\e[31mcall\e[0m", "jmp" => "\e[31mjmp\e[0m", );
And Im using it like so:
s/(^.*<)\:([a-z]+)>/$1$inst{$2}/;
Now, this all works fine as long as the found variable, $2, exists as a key in the hash. I was wondering if anyone here have some neat way of making it possible to add some kind of "default" key in the hash (without having some kind of function ofcource, that checks). Something like:
"default" => "\e[31m$the_key\e[0m",
So, the "default" is used if nothing else matches... Yes, a function can be used, but I thought there must be some cool perlish way doing this! ;)

Thanks,
Ace

Replies are listed 'Best First'.
Re: Having a "default" hash value!
by blokhead (Monsignor) on Feb 26, 2006 at 00:04 UTC
    You're right.. the best way to do this is to just check for the key's existence in the hash (perhaps factored into some function). But since you asked for a snazzy Perlish way, you could tie the hash to return a specific value when the key doesn't exist.

    I was surprised not to see something that does this on CPAN. Perhaps I didn't search for the right thing. Either way, it's a pretty simple tie interface:

    package Tie::Hash::DefaultVal; require Tie::Hash; @ISA = qw[Tie::ExtraHash]; sub TIEHASH { my ($pkg, $default) = @_; bless [ {}, $default ], $pkg; } sub FETCH { my ($self, $key) = @_; exists $self->[0]{$key} ? $self->[0]{$key} : $self->[1]; }
    The to use it...
    tie my %h, Tie::Hash::DefaultVal => "default-val"; %h = ( foo => "foo-val", bar => "bar-val" ); print "\$h{$_} = $h{$_}\n" for qw[ foo bar nonexistant ]; __OUTPUT__ $h{foo} = foo-val $h{bar} = bar-val $h{nonexistant} = default-val

    blokhead

Re: Having a "default" hash value!
by borisz (Canon) on Feb 26, 2006 at 00:13 UTC
    Here is one way:
    s/(^.*<)\:([a-z]+)>/ "$1" . ( exists $inst{ $2 } ? $inst{ $2 } : $inst +{ default } ) /e;
    or
    s/(^.*<)\:([a-z]+)>/ "$1" . ( $inst{ $2 } || $inst{ default } ) /e;
    Boris
Re: Having a "default" hash value!
by graff (Chancellor) on Feb 26, 2006 at 14:34 UTC
    It looks like you're just doing the same thing to all the strings: you're wrapping some sort of terminal-display escape sequence around each matched string, but it's always the same escape sequence ( "\e[31m ... \e[0m"). So why do you need a look-up hash at all?

    Also, it looks like you're keeping the open-angle-bracket but deleting the close-angle-bracket -- is that intentional, or a bug?

    Here's how I would do it (assuming the close-angle-bracket should be kept):

    my $openesc = "\e[31m"; my $closesc = "\e[0m"; s/^(.*<)\:([a-z]+)/$1$openesc$2$closesc/;
      Ah, well, I got that escape code from Term::Color actually :) Dont ask me why its like that, but it works... I dont get the left bracket either... there was no right bracket in the code in that module either. Also, the code is just part of a bigger hash, where I also have \e[32m \e[33m etc... counting up to 47 or so...
        My comment about "deleting the right angle bracket" was not about the escape codes, which always use a single left-square bracket after the ascii "esc" character, because... well, whoever thought it up must have felt it was a good idea at the time.

        I was pointing out that your regex substitution went like this:

        s/(^.*<)\:([a-z]+)>/$1$hash{$2}/;
        Note that you are keeping the left-angle bracket ("<") as part of the first capture ($1), but you are not keeping the associated right-angle bracket (">") -- that one is being deleted, because it's part of the matched pattern, but not part of the replacement string.

        If that's what you want, fine. I just thought it looked a bit like a bug.

Re: Having a "default" hash value!
by QM (Parson) on Feb 26, 2006 at 16:39 UTC
    You already have the keys to match, so why not match them? Then if it doesn't match, have a backup s///. (Also implementing graff's suggestion).
    my $keys = join '|', keys %inst; my $prefix = 'something'; my $suffix = 'else'; s/(^.*<)\:($keys)>/$1\e[31m$2\e[0m>/ or s/(^.*<)\:([a-z]+)>/$1$prefix$2$suffix>/

    -QM
    --
    Quantum Mechanics: The dreams stuff is made of

Re: Having a "default" hash value!
by Ace128 (Hermit) on Feb 26, 2006 at 01:21 UTC
    Ah, cool. Thanks ppl, but why Reputation: -1 ?
    Forgott to say that I couldnt just call a sub inside the substitution...