Perl: Matching hash keys to a regular expression

前端 未结 4 1725
渐次进展
渐次进展 2020-12-10 11:38

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 = ( \'twelv         


        
相关标签:
4条回答
  • 2020-12-10 12:01

    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/ );
    
    0 讨论(0)
  • 2020-12-10 12:05

    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;
    
    0 讨论(0)
  • 2020-12-10 12:06

    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;
    
    0 讨论(0)
  • 2020-12-10 12:22

    There's no built-in way, but there's Tie::Hash::Regex on CPAN.

    0 讨论(0)
提交回复
热议问题