Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl: Matching hash keys to a regular expression

Tags:

hash

perl

I'm wondering if Perl has a built-in way to check for the existence of a hash element with a key matching a particular regex. For example:

my %h = ( 'twelve' => 12, 'thirteen' => 13, 'fourteen' => 14 );

I'm wondering if there is any way to do this:

print "We have 12\n" if exists $h{twelve};
print "We have some teens\n" if exists $h{/.*teen$/};
like image 397
ajwood Avatar asked Mar 03 '11 14:03

ajwood


People also ask

How do I match a new line in a regular expression in Perl?

i think this will work,using the /s modifier, which mnemonically means to "treat string as a single line". This changes the behaviour of "." to match newline characters as well. In order to match the beginning of this comment to the end, we add the /s modifier like this: $str =~ s/<!

How get key from hash value in Perl?

Extracting Keys and Values from a Hash variable The list of all the keys from a hash is provided by the keys function, in the syntax: keys %hashname . The list of all the values from a hash is provided by the values function, in the syntax: values %hashname . Both the keys and values function return an array.

Does Perl use regex?

Regular Expression (Regex or Regexp or RE) in Perl is a special text string for describing a search pattern within a given text. Regex in Perl is linked to the host language and is not the same as in PHP, Python, etc. Sometimes it is termed as “Perl 5 Compatible Regular Expressions“.

How do I print a key and value hash in Perl?

The Perl print hash can used $ symbol for a single hash key and its value. The Perl print hash can use the % symbol for multiple hash keys and their values. The Perl print hash with “foreach” loop syntax is below.


3 Answers

The smart match operator does this (available since Perl v5.10).

$a      $b        Type of Match Implied    Matching Code
======  =====     =====================    =============
...
Regex   Hash      hash key grep            grep /$a/, keys %$b
...

Sample usage:

# print if any key in %h ends in "teen"
print "We have some teens\n" if /.*teen$/ ~~ %h;
like image 151
mob Avatar answered Oct 03 '22 21:10

mob


In addition to the other answers here you can also do this with perl's grep:

print "We have some teens\n" if grep {/.*teen/} keys %h;
like image 35
Flexo Avatar answered Oct 03 '22 21:10

Flexo


Yeah, it's called:

use List::Util qw<first>;

# Your regex does not compile perhaps you mean /teen$/
my $value = $hash{ ( first { m/teen/ } keys %hash ) || '' };

(Before smart match, that is. See mob's answer for smart match.)

You could also sort the keys:

my $value = $hash{ ( first { m/teen/ } sort keys %hash ) || '' };

I would freeze this into an "operation":

use Scalar::Util qw<reftype>;

sub values_for_keys_like (\[%$]$) {
    my $ref = reftype( $_[0] ) eq 'HASH' ? $_[0] : $$_[0];
    return unless my @keys = keys %$ref;

    my $regex = shift;
    # allow strings
    $regex    = qr/$regex/ unless my $typ = ref( $regex );
    # allow regex or just plain ol' filter functions.
    my $test  = $typ eq 'CODE' ? $regex : sub { return unless m/$regex/; 1 };

    if ( wantarray ) { 
        return unless my @k = grep { defined $test->( $_ ) } @keys;
        return @$ref{ @k };
    }
    else {
        return unless my $key = first { defined $test->( $_ ) } @keys;
        return $ref->{ $key };
    }
}

And you could use it like so:

my $key = values_for_keys_like( %hash => qr/teen/ );

Or

my $key = values_for_keys_like( $base->{level_two}{level_three} => qr/teen/ );
like image 30
Axeman Avatar answered Oct 03 '22 21:10

Axeman