嗨,我有一个任意深度的perl哈希。我想用其他东西替换整个结构中的字符串。
这样做的正确方法是什么?
我做了类似的事
#convert the hash to string for manipulation
my $data = YAML::Dump(%hash);
# do manipulation
---
---
# time to get back the hash
%hash = YAML::Load($data);
答案 0 :(得分:3)
您的想法对我来说似乎非常危险,因为很难确定替换不会破坏YAML::Dump
输出中的某些内容,这会阻止结果再次被读回,或者更糟,这将改变散列结构,因为它在转储字符串中表示。如果您尝试执行的操作是将:
替换为,将
’
替换为'
,或者某种类似的东西,该怎么办?
我可能会做更像这样的事情:
use Scalar::Util 'reftype';
# replace $this with $that in key names and string values of $hash
# recursively apply replacement in hash and all its subhashes
sub hash_replace {
my ($hash, $this, $that) = @_;
for my $k (keys %$hash) {
# substitution in value
my $v = $hash->{$k};
if (ref $v && reftype($v) eq "HASH") {
hash_replace($v, $this, $that);
} elsif (! ref $v) {
$v =~ s/$this/$that/og;
}
my $new_hash = {};
for my $k (keys %$hash) {
# substitution in key
(my $new_key = $k) =~ s/$this/$that/og;
$new_hash->{$new_key} = $hash->{$k};
}
%$hash = %$new_hash; # replace old keys with new keys
}
我在这里使用的s/…/…/
替换可能不适合您的任务;你应该随意使用别的东西。例如,您可以传递两个函数$this
和$that
,而不是字符串$key_change
和$val_change
,它们分别应用于键和值,返回修改后的版本。请参阅以下######
行:
use Scalar::Util 'reftype';
# replace $this with $that in key names and string values of $hash
# recursively apply replacement in hash and all its subhashes
sub hash_replace {
my ($hash, $key_change, $val_change) = @_;
for my $k (keys %$hash) {
# substitution in value
my $v = $hash->{$k};
if (ref $v && reftype($v) eq "HASH") {
hash_replace($v, $key_change, $val_change);
} elsif (! ref $v) {
$v = $val_change->($v); #######
}
}
my $new_hash = {};
for my $k (keys %$hash) {
# substitution in key
my $new_key = $key_change->($k); #######
$new_hash->{$new_key} = $hash->{$k};
}
%$hash = %$new_hash;
}
答案 1 :(得分:2)
这是攻击它的一种方法,通过哈希递归。在此代码中,您将传递sub
,它可以对嵌套哈希中的每个值执行任何操作。此代码仅修改值,而不是键,并忽略嵌套结构中的其他引用类型(即标量引用,数组引用)。
#!/usr/bin/perl -w
use Modern::Perl;
## Visit all nodes in a nested hash. Bare-bones.
sub visit_hash
{
my ($start, $sub) = @_;
my @q = ( $start );
while (@q) {
my $hash = pop @q;
foreach my $key ( keys %{$hash} ) {
my $ref = ref($hash->{$key});
if ( $ref eq "" ) { # not a reference
&$sub( $hash->{$key} );
next;
}
if ( $ref eq "HASH" ) { # reference to a nested hash
push @q, $hash->{$key};
next;
}
# ignore other reference types.
}
}
}
以下是一个如何使用它的示例,在嵌套哈希中用e
替换E
:
# Example of replacing a string in all values:
my %hash =
(
a => "fred",
b => "barney",
c => "wilma",
d => "betty",
nest1 =>
{
1 => "red",
2 => "orange",
3 => "green"
},
nest2 =>
{
x => "alpha",
y => "beta",
z => "gamma"
},
);
use YAML::XS;
print "Before:\n";
print Dump( \%hash );
# now replace 'e' with 'E' in all values.
visit_hash( \%hash, sub { $_[0] =~ s/e/E/g; } );
print "After:\n";
print Dump( \%hash );