How to use s/ for the keys in a hash? - perl

I have a hash %defines_3 which looks like this
'PIOMUX2_UART_3_TXD' => 'CONFIG_PIO31_6_SELECTOR',
'PIOMUX_UART_1_TXD' => 'CONFIG_PIO22_7_SELECTOR',
'PIOMUX_UART_11_TXD' => 'CONFIG_PIO0_4_SELECTOR',
'PIOMUX_UART_10_TXD' => 'CONFIG_PIO0_1_SELECTOR',
'PIOMUX2_UART_1_TXD' => 'CONFIG_PIO25_2_SELECTOR',
'PIOMUX_UART_3_TXD' => 'CONFIG_PIO32_6_SELECTOR',
To change some parts from all keys and values I did like this :
for (values %defines_3)
{
s/CONFIG_/PIO_M_U_/g;
s/_SELECTOR//g;
}
for (keys %defines_3)
{
s/_TXD//g;
}
print Dumper \%defines_3;
after which I am getting this :
'PIOMUX2_UART_3_TXD' => 'PIO_M_U_PIO31_6',
'PIOMUX_UART_1_TXD' => 'PIO_M_U_PIO22_7',
'PIOMUX_UART_11_TXD' => 'PIO_M_U_PIO0_4',
'PIOMUX_UART_10_TXD' => 'PIO_M_U_PIO0_1',
'PIOMUX2_UART_1_TXD' => 'PIO_M_U_PIO25_2',
'PIOMUX_UART_3_TXD' => 'PIO_M_U_PIO32_6',
So basically I am not able to substitute the keys but the values are being substituted the way i want by using s/ . How to change keys?

values() are producing lvalues which are due foreach aliased to $_ and thus can be directly changed. keys() must be deleted from hash in order to be changed,
for (keys %defines_3) {
my $v = delete $defines_3{$_};
s/_TXD//g;
$defines_3{$_} = $v;
}
or for newer perl which has support for /r switch,
for (keys %defines_3) {
$defines_3{ s/_TXD//gr } = delete $defines_3{$_};
}

You can't rename hash keys, as they are stored as simple C strings and not Perl scalar variables. To achieve the same effect you can delete the hash element and reinsert it using a new key.
Usefully, the delete operator returns the hash element's value, so you could write it like this.
Note that it is normally unwise to modify a hash or an array while you are iterating over it, but it is safe in this instance because the keys %data expression returns a fixed list of all of the hash keys that is separate from the hash itself.
use strict;
use warnings;
my %data = (
PIOMUX2_UART_3_TXD => 'CONFIG_PIO31_6_SELECTOR',
PIOMUX_UART_1_TXD => 'CONFIG_PIO22_7_SELECTOR',
PIOMUX_UART_11_TXD => 'CONFIG_PIO0_4_SELECTOR',
PIOMUX_UART_10_TXD => 'CONFIG_PIO0_1_SELECTOR',
PIOMUX2_UART_1_TXD => 'CONFIG_PIO25_2_SELECTOR',
PIOMUX_UART_3_TXD => 'CONFIG_PIO32_6_SELECTOR',
);
for my $key ( keys %data) {
(my $new_key = $key) =~ s/_TXD$//;
(my $new_val = delete $data{$key}) =~ s/^CONFIG_(.+)_SELECTOR$/PIO_M_U_$1/;
$data{$new_key} = $new_val;
}
use Data::Dump;
dd \%data;
output
{
PIOMUX2_UART_1 => "PIO_M_U_PIO25_2",
PIOMUX2_UART_3 => "PIO_M_U_PIO31_6",
PIOMUX_UART_1 => "PIO_M_U_PIO22_7",
PIOMUX_UART_10 => "PIO_M_U_PIO0_1",
PIOMUX_UART_11 => "PIO_M_U_PIO0_4",
PIOMUX_UART_3 => "PIO_M_U_PIO32_6",
}

This is probably easiest by using the pairmap function from List::Util. Its block is executed once for each key/value pair in the input list, and whatever list of values it returns is collected, like a regular map. This makes it easy to build a new hash out of an old one:
use 5.014; # for the s///r syntax
use List::Util qw( pairmap );
my %new_hash = pairmap {
( $a =~ s/_TXD$//r, $b =~ s/^CONFIG_(.+)_SELECTOR$/PIO_M_U_$1/r )
} %old_hash;
If you're stuck before 5.14 without the s///r syntax, you can do it with
use List::Util qw( pairmap );
my %new_hash = pairmap {
my ( $key, $val ) = ( $a, $b );
$key =~ s/_TXD$//;
$val =~ s/^CONFIG_(.+)_SELECTOR$/PIO_M_U_$1/;
( $key, $val )
} %old_hash;

Related

Accessing and modifying a nested hash based on a dot separated string

I have a string as input, say apple.mango.orange = 100
I also have a hash reference:
$inst = {
'banana' => 2,
'guava' => 3,
'apple' => {
'mango' => {
'orange' => 80
}
}
};
I want to modify the value of orange using the input string. Can someone please help me how I could do this?
I tried splitting the string into (key, value) pair. I then did the following on the key string:
my $key2 = "\$inst->{".$key."}";
$key2 =~ s/\./}->{/g;
$$key2 = $value;
This does not work as intended. Can someone help me out here? I have read the Perl FAQ about not using a variable value as variable but I am unable to think of an alternative.
You are building string that consists of (buggy) Perl code, but you never ask Perl to execute it. ...but that's not the right approach.
sub dive_val :lvalue {
my $p = \shift;
$p = \($$p->{$_}) for #_;
$$p
}
my #key = split /\./, "apple.mango.orange";
dive_val($inst, #key) = $value;
or
use Data::Diver qw( DiveVal );
my #key = split /\./, "apple.mango.orange";
DiveVal($inst, map \$_, #key) = $value;
Not only is a symbolic reference a very bad idea here, it doesn't even solve your problem. You're building an expression in $key2, and just jamming another dollar sign in front of its name won't make perl execute that code. For that you would need eval, which is another bad idea
You can install and use the Data::Diver module, which does exactly this sort of thing, or you can simply loop over the list of hash keys, picking up a new hash reference each time and assigning the value to the element with the last key
The biggest issue is actually parsing the incoming string into a list of keys and a value. This code implements a subroutine apply which applies the implied operation in the string to a nested hash. Unless you are confident of your data, it needs some error checking addingto make sure each of the keys in the list exists. The Data:;Dumper output is just to demonstrate the validity of the result
use strict;
use warnings 'all';
use Data::Dumper;
my $inst = { 'banana' => 2, 'guava' => 3, 'apple' => { 'mango' => { 'orange' => 80 } } };
my $s = 'apple.mango.orange = 100';
apply($s, $inst);
print Dumper $inst;
sub apply {
my ($operation, $data) = #_;
my ($keys, $val) = $operation =~ /([\w.]+)\s*=\s*(\d+)/;
my #keys = split /\./, $keys;
my $last = pop #keys;
my $hash = $data;
$hash = $hash->{$_} for #keys;
$hash->{$last} = $val;
}
output
$VAR1 = {
'banana' => 2,
'apple' => {
'mango' => {
'orange' => '100'
}
},
'guava' => 3
};

Automatically call hash values that are subroutine references

I have a hash with a few values that are not scalar data but rather anonymous subroutines that return scalar data. I want to make this completely transparent to the part of the code that looks up values in the hash, so that it doesn't have to be aware that some of the hash values may be anonymous subroutines that return scalar data rather than just plain old scalar data.
To that effect, is there any way to have the anonymous subroutines executed when their keys are accessed, without using any special syntax? Here's a simplified example that illustrates the goal and the problem:
#!/usr/bin/perl
my %hash = (
key1 => "value1",
key2 => sub {
return "value2"; # In the real code, this value can differ
},
);
foreach my $key (sort keys %hash) {
print $hash{$key} . "\n";
}
The output I would like is:
perl ./test.pl
value1
value2
Instead, this is what I get:
perl ./test.pl
value1
CODE(0x7fb30282cfe0)
As noted by Oleg, it's possible to do this using various more or less arcane tricks like tie, overloading or magic variables. However, this would be both needlessly complicated and pointlessly obfuscated. As cool as such tricks are, using them in real code would be a mistake at least 99% of the time.
In practice, the simplest and cleanest solution is probably to write a helper subroutine that takes a scalar and, if it's a code reference, executes it and returns the result:
sub evaluate {
my $val = shift;
return $val->() if ref($val) eq 'CODE';
return $val; # otherwise
}
and use it like this:
foreach my $key (sort keys %hash) {
print evaluate($hash{$key}) . "\n";
}
I don't believe that the words that others have written in disapproval of the tie mechanism are warranted. None of the authors seem to properly understand how it works and what core library backup is available
Here's a tie example based on Tie::StdHash
If you tie a hash to the Tie::StdHash class then it works exactly as a normal hash. That means there's nothing left to write except for methods that you may want to override
In this case I've overridden TIEHASH so that I could specify the initialisation list in the same statement as the tie command, and FETCH, which calls the superclass's FETCH and then makes a call to it if it happens to be a subroutine reference
Your tied hash will work as normal except for the change that you have asked for. I hope it is obvious that there is no longer a direct way to retrieve a subroutine reference if you have stored it as a hash value. Such a value will always be replaced by the result of calling it without any parameters
SpecialHash.pm
package SpecialHash;
use Tie::Hash;
use base 'Tie::StdHash';
sub TIEHASH {
my $class = shift;
bless { #_ }, $class;
}
sub FETCH {
my $self = shift;
my $val = $self->SUPER::FETCH(#_);
ref $val eq 'CODE' ? $val->() : $val;
}
1;
main.pl
use strict;
use warnings 'all';
use SpecialHash;
tie my %hash, SpecialHash => (
key1 => "value1",
key2 => sub {
return "value2"; # In the real code, this value can differ
},
);
print "$hash{$_}\n" for sort keys %hash;
output
value1
value2
Update
It sounds like your real situation is with an existing hash that looks something like this
my %hash = (
a => {
key_a1 => 'value_a1',
key_a2 => sub { 'value_a2' },
},
b => {
key_b1 => sub { 'value_b1' },
key_b2 => 'value_b2',
},
);
Using tie on already-populated variables isn't so neat as tying then at the point of declaration and then inserting the values as the data must be copied to the tied object. However the way I have written the TIEHASH method in the SpecialHash class makes this simple to do in the tie statement
If possible, it would be much better to tie each hash before you put data into it and add it to the primary hash
This program ties every value of %hash that happens to be a hash reference. The core of this is the statement
tie %$val, SpecialHash => ( %$val )
which functions identically to
tie my %hash, SpecialHash => ( ... )
in the previous code but dereferences $val to make the syntax valid, and also uses the current contents of the hash as the initialisation data for the tied hash. That is how the data gets copied
After that there is just a couple of nested loops that dump the whole of %hash to verify that the ties are working
use strict;
use warnings 'all';
use SpecialHash;
my %hash = (
a => {
key_a1 => 'value_a1',
key_a2 => sub { 'value_a2' },
},
b => {
key_b1 => sub { 'value_b1' },
key_b2 => 'value_b2',
},
);
# Tie all the secondary hashes that are hash references
#
for my $val ( values %hash ) {
tie %$val, SpecialHash => ( %$val ) if ref $val eq 'HASH';
}
# Dump all the elements of the second-level hashes
#
for my $k ( sort keys %hash ) {
my $v = $hash{$k};
next unless ref $v eq 'HASH';
print "$k =>\n";
for my $kk ( sort keys %$v ) {
my $vv = $v->{$kk};
print " $kk => $v->{$kk}\n"
}
}
output
a =>
key_a1 => value_a1
key_a2 => value_a2
b =>
key_b1 => value_b1
key_b2 => value_b2
There's a feature called "magic" that allows code to be called when variables are accessed.
Adding magic to a variable greatly slows down access to that variable, but some are more expensive than others.
There's no need to make access to every element of the hash magical, just some values.
tie is an more expensive form of magic, and it's not needed here.
As such, the most efficient solution is the following:
use Time::HiRes qw( time );
use Variable::Magic qw( cast wizard );
{
my $wiz = wizard(
data => sub { my $code = $_[1]; $code },
get => sub { ${ $_[0] } = $_[1]->(); },
);
sub make_evaluator { cast($_[0], $wiz, $_[1]) }
}
my %hash;
$hash{key1} = 'value1';
make_evaluator($hash{key2}, sub { 'value2#'.time });
print("$hash{$_}\n") for qw( key1 key2 key2 );
Output:
value1
value2#1462548850.76715
value2#1462548850.76721
Other examples:
my %hash; make_evaluator($hash{key}, sub { ... });
my $hash; make_evaluator($hash->{$key}, sub { ... });
my $x; make_evaluator($x, sub { ... });
make_evaluator(my $x, sub { ... });
make_evaluator(..., sub { ... });
make_evaluator(..., \&some_sub);
You can also "fix up" an existing hash. In your hash-of-hashes scenario,
my $hoh = {
{
key1 => 'value1',
key2 => sub { ... },
...
},
...
);
for my $h (values(%$hoh)) {
for my $v (values(%$h)) {
if (ref($v) eq 'CODE') {
make_evaluator($v, $v);
}
}
}
Yes you can. You can either tie hash to implementation that will resolve coderefs to their return values or you can use blessed scalars as values with overloaded mehods for stringification, numification and whatever else context you want to resolve automatically.
One of perl's special features for just such a use case is tie. This allows you to attach object oriented style methods, to a scalar or hash.
It should be used with caution, because it can mean that your code is doing really strange things, in unexpected ways.
But as an example:
#!/usr/bin/env perl
package RandomScalar;
my $random_range = 10;
sub TIESCALAR {
my ( $class, $range ) = #_;
my $value = 0;
bless \$value, $class;
}
sub FETCH {
my ($self) = #_;
return rand($random_range);
}
sub STORE {
my ( $self, $range ) = #_;
$random_range = $range;
}
package main;
use strict;
use warnings;
tie my $random_var, 'RandomScalar', 5;
for ( 1 .. 10 ) {
print $random_var, "\n";
}
$random_var = 100;
for ( 1 .. 10 ) {
print $random_var, "\n";
}
As you can see - this lets you take an 'ordinary' scalar, and do fruity things with it. You can use a very similar mechanism with a hash - an example might be to do database lookups.
However, you also need to be quite cautious - because you're creating action at a distance by doing so. Future maintenance programmers might well not expect your $random_var to actually change each time you run it, and a value assignment to not actually 'set'.
It can be really useful for e.g. testing though, which is why I give an example.
In your example - you could potentially 'tie' the hash:
#!/usr/bin/env perl
package MagicHash;
sub TIEHASH {
my ($class) = #_;
my $self = {};
return bless $self, $class;
}
sub FETCH {
my ( $self, $key ) = #_;
if ( ref( $self->{$key} ) eq 'CODE' ) {
return $self->{$key}->();
}
else {
return $self->{$key};
}
}
sub STORE {
my ( $self, $key, $value ) = #_;
$self->{$key} = $value;
}
sub CLEAR {
my ($self) = #_;
$self = {};
}
sub FIRSTKEY {
my ($self) = #_;
my $null = keys %$self; #reset iterator
return each %$self;
}
sub NEXTKEY {
my ($self) = #_;
return each %$self;
}
package main;
use strict;
use warnings;
use Data::Dumper;
tie my %magic_hash, 'MagicHash';
%magic_hash = (
key1 => 2,
key2 => sub { return "beefcake" },
);
$magic_hash{random} = sub { return rand 10 };
foreach my $key ( keys %magic_hash ) {
print "$key => $magic_hash{$key}\n";
}
foreach my $key ( keys %magic_hash ) {
print "$key => $magic_hash{$key}\n";
}
foreach my $key ( keys %magic_hash ) {
print "$key => $magic_hash{$key}\n";
}
This is slightly less evil, because future maintenance programmers can use your 'hash' normally. But dynamic eval can shoot the unwary in the foot, so still - caution is advised.
And alternative is to do it 'proper' object oriented - create a 'storage object' that's ... basically like the above - only it creates an object, rather than using tie. This should be much clearer for long term usage, because you won't get unexpected behaviour. (It's an object doing magic, which is normal, not a hash that 'works funny').
You need to identify when a code ref is present, then execute it as an actual call:
foreach my $key (sort keys %hash) {
if (ref $hash{$key} eq 'CODE'){
print $hash{$key}->() . "\n";
}
else {
print "$hash{$key}\n";
}
}
Note that you may consider making all of the hash values subs (a true dispatch table) instead of having some that return non-coderefs and some that return refs.
However, if you define the hash as such, you don't have to do any special trickery when it comes time to use the hash. It calls the sub and returns the value directly when the key is looked up.
key2 => sub {
return "value2";
}->(),
No, not without some ancillary code. You are asking for a simple scalar value and a code reference to behave in the same way. The code that would do that is far from simple and also injects complexity between your hash and its use. You might find the following approach simpler and cleaner.
You can make all values code references, making the hash a dispatch table, for uniform invocation
my %hash = (
key1 => sub { return "value1" },
key2 => sub {
# carry on some processing ...
return "value2"; # In the real code, this value can differ
},
);
print $hash{$_}->() . "\n" for sort keys %hash;
But of course there is a minimal overhead to this approach.

String Parsing for nested parenthesis in perl

The issue is when I try to compare the input to the output file, i am unable to handle the nesting of the parenthesis, and the complexity needs to be very low. is there a parsing module for this? compatible to 5.8.4. I found modules but they needed at least 5.10.:(
Input
(K1=V1,K2=V2,K3=V3(K2=V2.K5=V5)K6=V6(K7=V7,K8=V8(K9=V9,K10=V10)K11=V11)K12=V12,K13=V13)
OUTPUT FILE
(K0=V0,K1=V1,K2=V2,K3=V3(K1=V1,K2=V2,K4=V4,K5=V5,K14=V14),K15=V15,K6=V6(K18=V18,K7=V7,K19=V19,K8=V8(K20=V20,K9=V9,K16=V16,K10=V10,K21=V21)K11=V11)K12=V12,K13=V13,K22=V22)
I need to pick up each key value pair from input and one by one verify from the output file that the value is the same. if not
I need to store the key with the existing value.( The issue is with the nesting )
INPUT
K3=V3(K2=V2,K5=V5)
OUTPUT
K3=V3(K1=V1,K2=V2,K4=V4,K5=V5,K14=V14)
The issue is that "K2=V2" inside the V3 value is to be checked inside the V3 value in the output file. So I cannot just use a regular expression to do that as K2=V2 may appear outside the V3 parenthesis too.
I was trying to create a hash of a hash of a hash but failed. could someone suggest a way I could achieve this?
The following code builds the hash of hashes. Note that values (V3) are lost if they contain an inner hash.
#!/usr/bin/perl
use warnings;
use strict;
use Data::Dumper;
sub to_hash {
my $string = shift;
$string =~ s/^\( | \)$//gx; # Remove the outer parentheses.
my #stack = {};
my #keys;
while (length $string) {
$string =~ s/^([^,=()]+) = ([^(),]*)//x or die $string;
my ($key, $value) = ($1, $2);
$stack[-1]{$key} = $value;
next if $string =~ s/^,//;
if ($string =~ s/^\(//) {
push #stack, {};
push #keys, $key;
} elsif ($string =~ s/^\),?//) {
my $last = pop #stack;
$stack[-1]{ pop #keys } = $last;
}
}
return $stack[0]
}
my $input = '(K1=V1,K2=V2,K3=V3(K2=V2,K5=V5)K6=V6(K7=V7,K8=V8(K9=V9,K10=V10)K11=V11)K12=V12,K13=V13)';
print Dumper to_hash($input);
Output
$VAR1 = {
'K2' => 'V2',
'K13' => 'V13',
'K6' => {
'K7' => 'V7',
'K8' => {
'K9' => 'V9',
'K10' => 'V10'
},
'K11' => 'V11'
},
'K3' => {
'K2' => 'V2',
'K5' => 'V5'
},
'K12' => 'V12',
'K1' => 'V1'
};
Nested parens either suggests an application of Text::Balanced and its extract_bracketed function, or building yourself a little parser subclass on Parser::MGC. Using the latter to build a little "convert string into data structure" parser is usually pretty straightforward for simple examples like this.

Perl Tie::IxHash - is there an 'each' method?

Tie::IxHash produces an object that has a mostly-complete set of behaviors as both an array and a hash. But I'm not finding the equivalent of the each function, which returns (key,value) pairs.
Have I just overlooked it?
If I have to roll my own, I'd have thought something like this would work:
use Tie::IxHash;
$t = Tie::IxHash->new( a,1,b,2,c,3 );
while (($x1, $x2) = map { $_ => $t->Values($_) } $t->Keys ) { say "$x1 => $x2"; }
But the output was an infinite series of
a => 1
... for reasons that aren't clear to me yet.
Anybody able to suggest how to achieve each with a tied hash?
Tie::IxHash doesn't have an Each method, but you can use Perl's each function on the tied hash:
use Tie::IxHash;
my $t = tie my %hash, 'Tie::IxHash';
#hash{qw/a b c d e/} = (1, 2, 3, 4, 5);
# using the tied hash
while (my ($key, $val) = each %hash) {
print "$key => $val\n";
}
# using the OO interface (interchangeably)
foreach my $key ($t->Keys) {
my $val = $t->FETCH($key);
print "$key => $val\n";
}
Note that $t->Values($key) won't work. This method expects an index not a key. This will work:
foreach (0 .. $t->Length - 1) {
my ($key, $val) = ($t->Keys($_), $t->Values($_));
...
}

Perl: Matching hash keys to a regular expression

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$/};
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;
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;
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/ );
There's no built-in way, but there's Tie::Hash::Regex on CPAN.