2011-01-24 68 views
6

G'Day,在Perl中包含Hashes內的哈希

我目前正致力於從大量小哈希中創建大哈希。假設這些較小的散列是在每個文件中定義的,然後可以通過較大的散列來包含。

對於例如,讓我們來看看一些小的哈希

文件personcontact.pl

return { 
      \'firstname\' => { 
       \'__type\' => \'String\' 
      }, 
     \'lastname\' => { 
      \'__type\' => \'String\' 
      }, 
     %{include("/tmp/address.pl")} 
    } 

文件address.pl

return { 
     \'address\' => { 
     \'street\' => { 
      \'__type\' => \'String\' 
      }, 
     \'unit\' => { 
      \'__type\' => \'String\', 
      \'__validation_function\' => { 
       \'is_a_number\' => \'\' 
      }, 
      \'__schema_constraints\' => { 
       \'is_not_null\' => \'\' 
      } 
     }, 
     \'suburb\' => { 
      \'__type\' => \'String\' 
     }, 
     \'__type\' => \'ARRAY\' 
     } 
    } 

而且我已經得到了相當數量的這些...

我試圖重新創建的方式有h的使用include子程序,它看起來像這樣:

sub include { 
my ($filename) = @_; 
my $file; 
open(my $fh, "<", $filename) or die ("FILEOPEN: $!"); 
while(my $line = <$fh>) { $file .= $line; } 
my $result = eval $file; 
die("EVAL: [email protected]") if [email protected]; 
close($fh) or die("FILECLOSE: $!"); 
return $result; 
} 

我知道我必須做一些錯誤,但我不知道是什麼。我不斷收到類似Useless use of a variable in void context at (eval 11) line 4, <SCHEMAFILE> line 6Odd number of elements in anonymous hash at (eval 11) line 5, <SCHEMAFILE> line 6的錯誤。我不知道如何去尋找(eval 11)第4-3行,第6行。任何有關使用Perl調試器或任何可能出錯的指針的建議都將非常感激。

謝謝!

+2

無需逐行閱讀。通過在讀取文件之前加入`local $ /;`來使用「slurp模式」,並將`while(my $ line ...)`改爲`my $ line = <$fh>;``。 – Mikel 2011-01-24 04:35:21

回答

11

歡迎來到Perl。我希望你有一個很好的學習和使用它的時間。

就業務,從哪裏開始?我在這裏有很多要說的。

首先,這是不必要的冒險通過評估文件加載數據。如果您只想要序列化數據,請嘗試使用JSON::XSYAML,或者甚至使用Storable。如果你想要一個配置文件,CPAN上有許多模塊可以幫助完成這項任務。檢查出Config::Any

如果你想創建數據結構來通過eval加載(這不是一個好主意),Data::Dumper會生成創建任何數據結構所需的perl代碼。我提到它的主要原因是它比串行器更有用作爲調試輔助工具。

現在是照顧的,如果要加載一個文件,並評估它(同樣,沒有最好在幾乎所有情況下的想法),你應該看dorequire

my $stuff = do 'address.pl'; 

但是不這樣做。字符串eval是一種通常最好未使用的工具。 99%的時間,如果您打算使用字符串評估,請停下來思考解決問題的另一種方法。 Do是一個隱含的eval,所以它也是很重要的。

的Perl爲您提供了大量的工具做有風險的,強大的魔法。成爲高級Perl編程的很大一部分在於理解哪些事情是有風險的,爲什麼以及何時使用它們是有意義的。不要指望Perl用圍牆和大門來保護你,以保證你的安全。認真考慮拿起Effective Perl ProgrammingPerl Best Practices的副本。作爲一個新手,第一次閱讀時會有很多事情要做,但是隨着你的成長和學習,任何一本書都可以成爲一個很好的參考。

下一個話題,你試圖用所有那些逃脫的引號實現世界上的什麼?看着那些東西讓我頭痛! Perl有some very, very nice quoting operators,您可以使用它來避免在文字字符串中亂用引號。

=>或胖逗號會自動引用左手邊(LHS),就像它只是字母數字一樣。但是,把所有的引號和逃脫都讓事情變得非常狡猾。

當您說\'address\' => {}時,Perl將此視爲\,即將「get reference」運算符應用於字符串文字。在這種情況下,一個未終止的字符串文字,因爲你從未提供第一個之後未轉義的'

如果你的目標是利用'address',報價和全部作爲哈希鍵,你可以這樣做:

my %foo = ("'address'" => 'blah'); 

如果你不想引號,這似乎是一個更爲通常使用的情況下,簡單地做:

my %foo = (address => 'blah'); 

對您收到的錯誤消息!一旦你瞭解了它們的含義,Perl就會有一些相當不錯的錯誤消息。在此之前,理解它們的意義可能有點困難。幸運的是,Perl帶有一個名爲splain的腳本:一個方便的花花公子工具,可以更詳細地解釋錯誤消息。您也可以使用diagnostics模塊自動獲取相同的擴展錯誤消息。現在

,如果我寫這個,我會做一些事情沿着這些路線:

gen_schema_files.pl - 寫JSON模式文件的文件。如果你願意,你可以手工編輯你的模式。如果您想提高可讀性,您可能還希望將輸出配置爲更漂亮。

#!/usr/bin/perl 

use JSON::XS; 
use File::Spec; 

use constant BASEDIR => '.'; 

# Key is the file name, value is the data to put into the file. 
my %schemata = (
    'address.json' => { 
     address => { 
      street => { __type => 'String' }, 
      unit => { 
       __type => 'String', 
       __validation_function => { is_a_number => '' }, 
       __schema_constraints => { is_not_null => '' } 
      }, 
      suburb => { __type => 'String' }, 
      __type => 'ARRAY' 
     }, 
    }, 

    'person_contact.json' => { 
     firstname => { __type => 'String' }, 
     lastname => { __type => 'String' }, 

     # Use a special key to indicate that additional files should be 
     # loaded into this hash. 
     INCLUDE => [qw(address.json)], 
    }, 

    # And so forth 
); 

for my $schema (keys %schemata) { 
    my $path = File::Spec->catfile(BASEDIR, $schema); 

    open my $fh, '>', $path 
     or die "Error opening '$path' for writing - $!\n"; 

    print $fh encode_json $schemata{$schema}; 
} 

load_schemas.pl - 這是加載模式和做的東西的代碼。我的只能被加載。我不知道你正在處理數據的方式...

#!/usr/bin/perl 
use strict; 
use warnings; 

use Data::Dumper; 

use JSON::XS; 
use File::Spec; 

use constant BASEDIR => '.'; 


my $schema = load_schema('person_contact.json'); 

print Dumper $schema; 


sub load_schema { 
    my $file = shift; 

    my $path = File::Spec->catfile(BASEDIR, $file); 

    open my $fh, '<', $path 
     or die "Error opening file '$path' - $!\n"; 

    my $json = join '', <$fh>; # reads a list of lines and cats them into one string. 
           # One way to slurp out of many. 

    my $schema = decode_json($json); 

    # Handle the inclusion stuff: 

    if(exists $schema->{INCLUDE}) { 
     # Copy the files to load into an array. 
     my @loadme = @{$schema->{INCLUDE}}; 
     # delete the magic special include key. 
     delete $schema->{INCLUDE}; 

     # Load each file and copy it into the schema hash. 
     for my $load (@loadme) { 
      my $loaded = load_schema($load); 

      # This is a bit of weird syntax. 
      # We are using a hash slice assignment to copy the loaded data into the existing hash. 
      # keys and values are guaranteed to come out in the same (random) order as each other. 
      # the @{$foo}{blahbhal} is how you dereference a hash reference as a slice. 
      @{$schema}{keys %$loaded} = values %$loaded; 
     } 
    } 

    return $schema; 
} 

我已經掩蓋了一些東西,但我試過有足夠的條件(詞彙,甚至行話要發表評論,如果你喜歡)讓你做有利可圖的搜索。

上面的代碼有幾個缺陷。它不會檢查循環包含(它會運行很長時間,最終會填滿內存和崩潰 - 不太好)。魔術鑰匙的選擇可能不太好。還有更多我還沒有想到。

Perldoc是一個了不起的資源,但有這麼多,需要一段時間才能學會找東西。看看Perl Data Structures CookbookArrays of Arrays tutorial。作爲初學者,我發現Perl Functions by Category section of perlfunc非常有幫助。

我想我會停下來,現在我已經寫了足夠多的文字來讓一般人失明。我希望你覺得這篇論文有用。再次歡迎,晚上好(請在適應當地時間的情況下調整,以便找到答案)。