Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw

Replace a hash key if it matches a regex

by walkingthecow (Friar)
on Sep 13, 2013 at 08:39 UTC ( #1053864=perlquestion: print w/replies, xml ) Need Help??
walkingthecow has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to strip a few characters from the end of my hash keys. Here's what I have, but it's not working:
$db_results{$_} = $1 if $db_results{$_} =~ /(BLAH\d{2}-\w)/ for keys $ +db_results;

Say the hash key is BLAH01-A05AFGH. I want the hash key to be BLAH01-A.

I assume this one is not too hard and that the fellow monks would know how to accomplish it.

UPDATE Sometimes I post a question and 10 minutes later answer it myself...
foreach (keys $db_results) { my $match = $1 if $_ =~ /(BLAH\d{2}-\w)/; $db_results->{$1} = delete $db_results->{$_}; + }
Putting the code here for anyone interested. Probably a better way to do it too, which I'd always be interested in. It's a hash of hashes and it kept my data structure intact, so that's good too.

Replies are listed 'Best First'.
Re: Replace a hash key if it matches a regex
by AnomalousMonk (Chancellor) on Sep 13, 2013 at 09:54 UTC
    foreach (keys $db_results) { my $match = $1 if $_ =~ /(BLAH\d{2}-\w)/; $db_results->{$1} = delete $db_results->{$_}; }

    The  $match variable isn't used in the quoted code, so I assume this is a cut-down fragment of working code in which it is subsequently used. If so, be aware that the usage
        my $scalar = $whatever if ... ;
    (conditional definition/initialization of a lexical) is a pre-state (5.10+) hack used to create a bastard state-like variable; it has all kinda weird side-effects and is officially Frowned Upon. Avoid it if you can — and you can, e.g.:
        my ($match) = $_ =~ /(whatever)/;
        do_something_with($match) if defined $match;
    or (assuming you're in a loop)
        my ($match) = $_ =~ /(whatever)/;
        next unless defined $match;

      Wait, this is new to me. Are you saying that this:
      my $foo = $1 if $_ =~ /regex/;
      is bad?

      The only alternative to that which I know is:
      if ( $_ =~ /regex/ ) { my $foo = $1; $db_results->{$foo} = delete $db_results->{$_}; }
      By the way, thanks for pointing out that I was not using $match. Late night.
        See perlsyn - Perl syntax for details:
        The behaviour of a my, state, or our modified with a statement modifier conditional or loop construct (for example, my $x if ... ) is undefined. The value of the my variable may be undef, any previously assigned value, or possibly anything else. Don't rely on it. Future versions of perl might do something different from the version of perl you try it out on. Here be dragons.

        You can use the following:

        if (my ($match) = $_ =~ /...(...).../) { $db_results->{$match} = delete $db_results->{$_} }

        For $_, you can omit the $_ =~ part.

        لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
        Are you saying ... is bad?

        Yes — or at least potentially very weird and certainly very easily avoided. I'm afraid I don't have time ATM to locate a good explanatory link. (Update: Thanks, choroba, for the link)

        The only alternative ... which I know ...

        Sorry, I added some examples of alternatives after my original reply without marking them as update material. BTW, another alternative (assuming you're in a loop):
            next unless $_ =~ /(whatever)/;
            my $foo = $1;

Re: Replace a hash key if it matches a regex
by Happy-the-monk (Abbot) on Sep 13, 2013 at 08:48 UTC

    Say the hash key is BLAH01-A05AFGH. I want the hash key to be BLAH01-A

    perl -e'use Data::Dumper; %hash=("BLAH01-A05AFGH0"=>17); for(keys %hash) { if (m/(BLAH\d{2}-\w)/) { $hash{$1} = delete $hash{$_} } }; print Dumper \%hash'

    $VAR1 = { 'BLAH01-A' => 17 };

    NB there's no check if the new key already exists... it will be overwritten if it does.

    Cheers, Sören

    Créateur des bugs mobiles - let loose once, run everywhere.
    (hooked on the Perl Programming language)

Re: Replace a hash key if it matches a regex
by ansh batra (Friar) on Sep 13, 2013 at 08:50 UTC

    Assuming you need to keep characters upto one more than the first occurence of "-"


      That doesn't seem to work:

      >perl -wMstrict -le "$_ = 'BLAH01-ARRRGH0GAG'; s/-./$`$&/; print qq{'$_'}; " 'BLAH01BLAH01-ARRRGH0GAG'

      Update: If  \K is available (5.10+), this works nicely:

      >perl -wMstrict -le "use 5.010; ;; $_ = 'BLAH01-ARRRGH0GAG'; s{ .*? - \w \K .* }''xms; print qq{'$_'}; " 'BLAH01-A'

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1053864]
Approved by hdb
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (5)
As of 2017-10-24 06:10 GMT
Find Nodes?
    Voting Booth?
    My fridge is mostly full of:

    Results (286 votes). Check out past polls.