2012-01-05 16 views
0

我使用Config :: General爲腳本加載安裝數據。作爲它的一部分,我希望腳本能夠在config數據中查找和替換值。由於這些值可以嵌套到多個層次,所以似乎最好的方法是使用遞歸函數來進行替換。我想出了以下似乎工作正常:通過perl散列進行遞歸的正確方法是什麼?

#!/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> 

有沒有更好的方法來做到這一點?而且,更重要的是,這個代碼中是否存在等待咬我的陷阱?

回答

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運行時是好的,有strictwarnings是更好的運行,並會抓住更多的潛在的錯誤。最後,有時你可以運行與間接對象語法問題,所以使用標準方法調用構造函數:

Config::General->new(-ConfigFile => \*DATA); 

,或者如果你喜歡的間接對象語法,使其明確加入::到封裝結束名稱:

new Config::General:: -ConfigFile => \*DATA; 
+0

謝謝Eric。好東西。至於警告,我使用「-w」標誌。舊習慣。閱讀警告雜注perldoc很明顯,我需要切換到顯式調用它。我們將看到打破肌肉記憶需要多長時間...... – 2012-01-05 23:39:57

相關問題