Reputation: 29
I have a hash, say "Identifier" with keys such as FACD,BDCD,DDSE,CDSD. I would like to search if the key "FXXD" is present in the hash "Identifier" by considering X to match any alphanumeric. In this scenario, it should come back with found as "FXXD" matches "FACD" considering X can be anything.
Can hash key search be done by adding a character to match anything?
Any idea would be really helpful?
Thanks in Advance!
Upvotes: 2
Views: 725
Reputation: 69284
If you're not too concerned with performance, you could use Tie::Hash::Regex.
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
use Tie::Hash::Regex;
my %hash : Regex;
%hash = (
FACD => 1,
BDCD => 1,
DDSE => 1,
CDSD => 1,
);
if (exists $hash{'F\w\wD'}) {
say 'Found key matching FXXD';
} else {
say 'No key matching FXXD';
}
[Full disclosure - I wrote this module as a stupid demonstration of tying. I don't really recommend that you use it in production.]
Upvotes: 1
Reputation: 52439
First, turn the X's in your string into a regular expression character class that matches a single alphanumeric character, and then the good old grep
/keys
:
#!/usr/bin/perl
use warnings;
use strict;
use feature qw/say/;
my $test = { FACD => 1, BDCD => 1, DDSE => 1, CDSD => 1, QFADD => 1 };
sub matches {
my ($hash, $key) = @_;
# X matches all alphanumeric characters
$key =~ s/X/[[:alnum:]]/g;
my $pat = qr/^$key$/;
return grep { m/$pat/ } keys %$hash;
}
for (qw/FXXD FXDD BXXX/) {
say $_, (matches($test, $_) ? " matches!" : " doesn't match!");
}
Upvotes: 5
Reputation: 66891
To select keys that satisfy a pattern
my @spec_keys = grep { /F..D/ } keys %identifier;
where the F..D
pattern can be anywhere in the key. If it should match the key without any leading or trailing characters then anchor it, /^F..D$/
.
Upvotes: 5
Reputation: 5962
No you can't. A single hash is the wrong approach for this kind of search.
If your keys are fixed sized, e.g. 4 characters long as per your example, you could use multiple hashes. Here is a sketch of the algorithm:
my %first = (
A => { AAAA => 1, ... all keys starting with A... },
...
);
my %second = {
A => { AAAA => 1, ... all keys having A as 2nd character... },
...
);
my %third = ...
my %fourth = ...
# match first (F) and last (D) character in key
my $matches_first = $first{F};
my $matches_last = $fourth{D};
my @matches =
grep { exists $matches_fourth->{$_} }
keys %{ $matches_first };
In a real program you would generate the contents of %first
etc from the list of keys and calculate the match code from the search pattern.
foreach my $c ('A'..'Z') {
$first{$c} = {};
$second{$c} = {};
$third{$c} = {};
$fourth{$c} = {};
}
foreach my $key (keys %identifier) {
my($c1, $c2, $c3, $c4) = split(//, $key);
$first{$c1}->{$key}++;
$second{$c2}->{$key}++;
$third{$c3}->{$key}++;
$fourth($c4}->{$key}++;
}
EDIT 2: Depending on the amount of your data it might also be possible to use a simple search function, e.g. for your example
my @matches = grep { /^F..D$/ } keys %identifier;
Upvotes: 1