Regex Perl在哈希中替换字符串
嗨,我有一个任意深度的perl哈希。我想用其他东西替换整个结构中的a字符串 正确的方法是什么 我做了这样的事Regex Perl在哈希中替换字符串,regex,perl,Regex,Perl,嗨,我有一个任意深度的perl哈希。我想用其他东西替换整个结构中的a字符串 正确的方法是什么 我做了这样的事 #convert the hash to string for manipulation my $data = YAML::Dump(%hash); # do manipulation --- --- # time to get back the hash %hash = YAML::Load($data); 您的想法对我来说似乎非常危险,因为很难确保替换不会破坏YAML::Dump输
#convert the hash to string for manipulation
my $data = YAML::Dump(%hash);
# do manipulation
---
---
# time to get back the hash
%hash = YAML::Load($data);
您的想法对我来说似乎非常危险,因为很难确保替换不会破坏
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\u change
和$val\u 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;
}
您的想法对我来说似乎非常危险,因为很难确保替换不会破坏
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\u change
和$val\u 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;
}
这里有一种攻击它的方法,通过哈希递归。在这段代码中,您传入一个
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 );
这里有一种攻击它的方法,通过哈希递归。在这段代码中,您传入一个
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 );
键、值或两者?键、值或两者?
标量在while
循环的条件下是多余的,因为条件始终是标量。@MJD:True。不幸的是,我的习惯是包含它,因为没有它我的其他程序员不太清楚。我不明白while(scalar@q)
如何比while(@q)
更清楚,因为前者需要理解晦涩且很少使用的scalar
操作符,但是好的。@MJD:我读过你的高阶Perl书籍。你比我的同事更精通perl::-)我们大多是EEs,而不是CS。我曾经想出一个理论,认为$#array
被过度使用,当它被使用时,通常是多余的或错误的。我做了一项研究,查看了Usenet上示例中发布的数百个$#array
的用法,发现我的理论是不正确的:$#array
在大约20%的时间里是冗余的或错误的。scalar
在while
循环的情况下是冗余的,因为一个条件总是一个标量。@MJD:True。不幸的是,我的习惯是包含它,因为没有它我的其他程序员不太清楚。我不明白while(scalar@q)
如何比while(@q)
更清楚,因为前者需要理解晦涩且很少使用的scalar
操作符,但是好的。@MJD:我读过你的高阶Perl书籍。你比我的同事更精通perl::-)我们大多是EEs,而不是CS。我曾经想出一个理论,认为$#array
被过度使用,当它被使用时,通常是多余的或错误的。我做了一项研究,查看了Usenet上示例中发布的数百个$#array
,发现我的理论是不正确的:$#array
在大约20%的时间里是多余的或错误的。当然,这会在开始时快照一组键,但这行在做什么,它如何不依赖于访问顺序<代码>$hash->{$new_key}删除$hash->{$k}
例如,如果我有(a=>1,b=>2)
,并且我的$key\u change
将a映射到b,b映射到c,那么$hash->{b}delete$hash->{a}
在我访问它之前,如果键碰巧返回('a',b')
,那么的操作将对进行clobbers操作。如果我的映射函数将a映射到b,b映射到a,那么没有访问顺序是安全的。当然,这会在开始时快照一组键,但是此行的作用是什么,它如何不依赖于访问顺序<代码>$hash->{$new_key}删除$hash->{$k}
例如,如果我有(a=>1,b=>2)
,并且我的$key\u change
将a映射到b,b映射到c,那么$hash->{b}delete$hash->{a}
在我访问它之前,如果键碰巧返回('a',b')
,那么的操作将对进行clobbers操作。如果我的映射函数映射