Possible to detect hash with more than one key? - perl

I am collecting data in a hash of hashes which looks like
$VAR1 = {
'502' => {
'user2' => '0'
},
'501' => {
'git' => '0',
'fffff' => '755'
},
'19197' => {
'user4' => '755'
}
};
The problem is in 501. Two keys may not occur. Is it possible to detect this?
Update
Fixed typo in hash.

If you are only going to store one key-value pair under each key of the main hash, why not use a 2-element array instead? That way you can check for existence before making each new insert, without needing to check the size of the hash or knowing what its keys are. The structure I'm proposing is this:
$VAR1 = {
'502' => [ 'user2', '0' ],
'501' => [ 'git', '0' ],
'19197' => [ 'user4', '755' ]
}

Assuming your hashref above is named $var :
my #bad = grep { scalar keys %{$var->{$_}} > 1 } keys %$var;
Results in an array of hash keys that have more than one hashref within them. Using your data above:
# perl test.pl
$VAR1 = {
'501' => {
'git' => '0',
'fffff' => '755'
},
'502' => {
'user2' => '0'
},
'19197' => {
'user4' => '755'
}
};
$VAR1 = '501';
Then you could access each element that is detected as bad with:
foreach my $key ( #bad ) {
# do something to or with $var->{$key}
}

keys(%{$VAR1{'501'}}) == 2 where the rest would be one.
Also, syntax error on that key, but I assume it's a typo.

Related

How to address specific array element in complex data structure in perl

I have a complex json data structure in perl like in the following example. I want to address an array element and store data.
Variable
$VAR1 = {
'dummy' => 'foo',
'profiles' => {
'Tags' => [
{
'###PLACEHOLDER###',
}
],
}
I can for example add an element at "###PLACEHOLDER###" but want later in the perl script to add beneath that Placeholder additional information.
Normally i would address these elements with $var->{profiles}->{Tags}->{PLACEHOLDER} but this is not working with an array.
I dont want to create everytime a foreach loop when i know the name exactly.
Any advice?
[UPDATE: used dpathr instead of dpath for the references to structures]
[UPDATE: used dpath instead of dpathr for the references to elements]
Data::DPath can do what you require. Here's code which returns a reference to any structure (hash or array) which contains an element whose value is ###PLACEHOLDER###:
use strict;
use warnings;
use Data::Dumper;
use Data::DPath qw[ dpath dpathr ];
my $struct = {
'dummy' => 'foo',
'profiles' => {
'ARRAY' => [ '###PLACEHOLDER###' ],
'HASH' => { key => '###PLACEHOLDER###' },
},
};
my $path = dpath( '//[value eq "###PLACEHOLDER###"]/..' );
my #matches = $path->match( $struct );
print Dumper \#matches;
It results in:
$VAR1 = [
[
'###PLACEHOLDER###'
],
{
'key' => '###PLACEHOLDER###'
}
];
If you want direct access to the element, change the path to
my $path = dpathr( '//*[value eq "###PLACEHOLDER###"]' );
with the result:
$VAR1 = [
\'###PLACEHOLDER###',
\'###PLACEHOLDER###'
];
It's not clear to me what you what "adding an element at ###PLACEHOLDER###" means. Elements can be added to arrays and hashes, and it's not clear to which array or hash you are referring.
To append an element to the array referenced by $var->{profiles}{Tags}, use
push #{ $var->{profiles}{Tags} }, $val;
This results in
$VAR1 = {
'dummy' => 'foo',
'profiles' => {
'Tags' => [
{
'###PLACEHOLDER###' => undef,
},
$val
],
}
To add an element to the hash referenced by the last element of the array referenced by $var->{profiles}{Tags}, use
$var->{profiles}{Tags}[-1]{$key} = $val;
This results in
$VAR1 = {
'dummy' => 'foo',
'profiles' => {
'Tags' => [
{
'###PLACEHOLDER###' => undef,
$key => $val,
},
],
}
Of course, if $key is ###PLACEHOLDER###, this results in
$VAR1 = {
'dummy' => 'foo',
'profiles' => {
'Tags' => [
{
'###PLACEHOLDER###' => $val,
},
],
}

Perl- Get Hash Value from Multi level hash

I have a 3 dimension hash that I need to extract the data in it. I need to extract the name and vendor under vuln_soft-> prod. So far, I manage to extract the "cve_id" by using the following code:
foreach my $resultHash_entry (keys %hash){
my $cve_id = $hash{$resultHash_entry}{'cve_id'};
}
Can someone please provide a solution on how to extract the name and vendor. Thanks in advance.
%hash = {
'CVE-2015-6929' => {
'cve_id' => 'CVE-2015-6929',
'vuln_soft' => {
'prod' => {
'vendor' => 'win',
'name' => 'win 8.1',
'vers' => {
'vers' => '',
'num' => ''
}
},
'prod' => {
'vendor' => 'win',
'name' => 'win xp',
'vers' => {
'vers' => '',
'num' => ''
}
}
},
'CVE-2015-0616' => {
'cve_id' => 'CVE-2015-0616',
'vuln_soft' => {
'prod' => {
'name' => 'unity_connection',
'vendor' => 'cisco'
}
}
}
}
First, to initialize a hash, you use my %hash = (...); (note the parens, not curly braces). Using {} declares a hash reference, which you have done. You should always use strict; and use warnings;.
To answer the question:
for my $resultHash_entry (keys %hash){
print "$hash{$resultHash_entry}->{vuln_soft}{prod}{name}\n";
print "$hash{$resultHash_entry}->{vuln_soft}{prod}{vendor}\n";
}
...which could be slightly simplified to:
for my $resultHash_entry (keys %hash){
print "$hash{$resultHash_entry}{vuln_soft}{prod}{name}\n";
print "$hash{$resultHash_entry}{vuln_soft}{prod}{vendor}\n";
}
because Perl always knows for certain that any deeper entries than the first one is always a reference, so the deref operator -> isn't needed here.

Hash not passing properly between functions

I set up a user hash in a function with the following,
push #{$profile{$index}{$infoName}}, $information
and print it using print Dumper(\%profile); index++; in the function it was set up it prints each of indexes
`$VAR1 = { '374' => { 'degree' => [ 'CS' ], 'birthdate' => [ '1973/12/13' ], 'gender' => [ 'M' ],...}
$VAR1 = { '375' => { 'degree' => [ 'CS' ], 'birthdate' => [ '1933/02/03' ], 'gender' => [ 'F' ],...}`
when i try to access this within another function's foreach loop using print "${$profile{$currIndex}{'gender'}}"; i get odd behaviour where the print returns an empty string and get some random numbers appear in the hash: '$VAR1 = { '4' => {}, '1' => {}, '3' => {}, '2' => {}, '378' => { 'birthdate' => [ '1961/03/29' ], 'gender' => ['F'],..}
How can i properly access the gender feild from within a loop?
push #{$profile{$index}{$infoName}}, $information;
print "${$profile{$currIndex}{'gender'}}";
I'm not even sure what the second line actually does. On my Ubuntu, perl produces an error: not a scalar reference.
What you want is, to print all array elements:
print "#{$profile{$currIndex}{'gender'}}\n";
or, to print the first:
print $profile{$currIndex}->{'gender'}->[0], "\n";
The leaf element is an array references and has to be dereferenced as such.
I'm not sure why you use there array references. In your sample data there are no multiple elements in the arrays. Probably you wanted to write simply this? -
$profile{$index}{$infoName} = $information;
...
print "$profile{$currIndex}{'gender'}\n";

How can I look and search for a key inside a heavily nested hash?

I am trying to check if a BIG hash has any keys from small hash and see if they exist, and if they do modify the BigHash with updated values from small hash.
So the lookup hash would look like this :
configure =(
CommonParameter => {
'SibSendOverride' => 'true',
'SibOverrideEnabledFlag' => 'true',
'SiPosition' => '8',
'Period' => '11'
}
)
But the BigHash is very very nested.. The key/hash CommonParameter from the small hash configure is there in the BigHash.
Can somebody help/suggest some ideas for me please?
Here is an example BigHash :
%BigHash = (
'SibConfig' => {
'CELL' => {
'Sib9' => {
'HnbName' => 'HnbName',
'CommonParameter' => {
'SibSendOverride' => 'false',
'SibMaskOverrideEnabledFlag' => 'false',
'SiPosition' => '0',
'Period' => '8'
}
}
}
},
)
I hope I was clear in my question. Trying to modify values of heavily nested BigHash based on Lookup Hash if those keys exist.
Can somebody help me? I am not approaching this in the right way. Is there a neat little key lookup fucntion or something available perhaps?
Give Data::Search a try.
use Data::Search;
#results = Data::Search::datasearch(
data => $BigHash, search => 'keys',
find => 'CommonParameter',
return => 'hashcontainer');
foreach $result (#results) {
# result is a hashref that has 'CommonParameter' as a key
if ($result->{CommonParameter}{AnotherKey} ne $AnotherValue) {
print STDERR "AnotherKey was ", $result->{CommonParameter}{AnotherKey},
" ... fixing\n";
$result->{CommonParameter}{AnotherKey} = $AnotherValue;
}
}

How do I access certain keys in a Perl nested hash?

I dumped a data structure:
print Dumper($bobo->{'issues'});
and got:
$VAR1 = {
'155' => {
'name' => 'Gender',
'url_name' => 'gender'
}
};
How can I extract 155?
How about if I have:
$VAR1 = {
'155' => {'name' => 'Gender', 'url_name' => 'gender'},
'11' => {'name' => 'Toddler', 'url_name' => 'toddler'},
'30' => {'name' => 'Lolo', 'url_name' => 'lolo'}
};
I want to print one key, i.e. the first or second to see the value of the key?
So, based on the example you posted, the hash looks like this:
$bobo = {
issues => {
155 => {
name => 'Gender',
url_name => 'gender',
},
},
};
'155' is a key in your example code. To extract a key, you would use keys.
my #keys = keys %{$bobo->{issues}};
But to get the value that 155 indexes, you could say:
my $val = $bobo->{issues}{155};
Then $val would contain a hashref that looks like this:
{
name => 'Gender',
url_name => 'gender'
}
Have a look at perldoc perlreftut.
It is a key in the hash referenced by $bobo->{'issues'}. So you would iterate through
keys %{$bobo->{'issues'}}
to find it.