我正在使用Config :: General来加载脚本的设置数据。作为其中的一部分,我希望脚本能够对配置数据中的值进行一些查找和替换。由于值可以嵌套多个级别,似乎最好的方法是使用递归函数来进行替换。我提出以下似乎工作正常:
#!/usr/bin/perl -w
use strict;
use Config::General;
use YAML::XS;
### Load in the config data and move it into the hash.
my $configObj = new Config::General(-ConfigFile => \*DATA);
my %config_hash = $configObj->getall;
### define the year to use as the replacement
my $current_year = (localtime())[5] + 1900;
### Call the function to update the data.
recursive_hash_replacement(\%config_hash, $current_year);
sub recursive_hash_replacement {
### Pull in the hash ref.
my $tmp_hash_ref = shift;
my $replacment_year = shift;
### Loop through all the keys in the hash ref.
for my $tmp_hash_key (keys %{$tmp_hash_ref}) {
### If the value is another hash ref, call the function recursively.
if(ref $tmp_hash_ref->{$tmp_hash_key} eq ref {}) {
recursive_hash_replacement($tmp_hash_ref->{$tmp_hash_key}, $replacment_year);
}
### otherwise, just update the value.
else {
$tmp_hash_ref->{$tmp_hash_key} =~ s{!YEAR!}{$replacment_year}g;
}
}
}
### Show the output with the updated values.
print Dump \%config_hash;
### Define the config data locally for testing.
__DATA__
key1 = /path/with/no/update
key2 = /path/with/new/!YEAR!/update
<level1>
<level2>
key3 = /another/!YEAR!/update
</level2>
</level1>
有更好的方法吗?而且,更重要的是,这段代码中是否有潜伏等待咬我的东西?
答案 0 :(得分:2)
您可以通过处理哈希值而不是键来简化一些事情。你还想测试其他类型的引用,因为在其他ref类型上盲目运行正则表达式可能不会做你想要的。
sub recursive_hash_replacement {
### unpack multiple args with list assignment:
my ($hash, $year) = @_;
### Loop through all the values in the hash ref.
for my $value (values %$hash) {
### If the value is another hash ref, call the function recursively.
if (ref $value) {
if (ref $value eq 'HASH') {
recursive_hash_replacement($value, $year);
}
else {
# handle other reftypes, or skip them, or throw an error
die "non hash reference: $value"
}
}
### otherwise, just update the value.
else {
$value =~ s{!YEAR!}{$year}g;
}
}
}
最后,在使用strict
运行时运行良好,使用strict
和warnings
运行会更好,并且会捕获更多潜在错误。最后,您有时会遇到间接对象语法的问题,因此对构造函数使用标准方法调用:
Config::General->new(-ConfigFile => \*DATA);
或者如果你喜欢间接对象语法,可以通过在包名末尾添加::
来明确它:
new Config::General:: -ConfigFile => \*DATA;
答案 1 :(得分:0)
值得一看CPAN上的Data::Visitor。这是Config::JFDI在幕后使用它进行替换的原因。