2011-01-24 5 views
6

G'Day,Perl의 해시에 해시 포함

저는 현재 많은 작은 해시에서 큰 해시를 만드는 중입니다. 이 작은 해시가 각각 파일에 정의 된 다음 더 큰 해시에 포함될 수 있다고 가정 해 보겠습니다.

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

파일 address.pl :

예를 들어, 몇 가지 작은 해시

파일 personcontact.pl 살펴 보자

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

그리고 이들의 상당수있어 ...

내가 다시 만들려고하는 방법은 시간이처럼 보이는 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 6 또는 Odd number of elements in anonymous hash at (eval 11) line 5, <SCHEMAFILE> line 6과 같은 오류가 계속 발생합니다. 나는 (에일 11) 라인 4-3, 라인 6을 찾는 방법에 대해 잘 모르겠습니다. Perl의 디버거 사용에 관한 제안이나 내가 잘못 될지도 모르는 부분에 대한 조언은 많은 도움이 될 것입니다.

감사합니다.

+2

줄 단위로 읽을 필요가 없습니다. 파일을 읽기 전에'local $ /;'을 넣어서 "slurp mode"를 사용하고'while $ myline ... '을'my $ line = <$fh>;'로 바꾼다. – Mikel

+0

팁 주셔서 감사! 당신이 짐작 했겠지만, 저는 Perl에 대해 상당히 새로운 것 같습니다. –

+3

YAML과 같은 것이 더 적절할 수도 있습니다. http://search.cpan.org/dist/YAML/lib/YAML.pm – Mikel

답변

11

Perl에 오신 것을 환영합니다. 나는 당신이 좋은 시간을 배우고 사용하기를 바랍니다.

어디서부터 시작하니? 나는 여기에서 할 말이 많다.

먼저 파일을 평가하여 데이터를로드하는 것이 불필요하게 위험합니다. 데이터를 직렬화하려는 경우 JSON::XS 또는 YAML 또는 심지어 Storable을 사용해보십시오. 설정 파일을 원한다면이 작업을 돕는 CPAN에 많은 모듈이 있습니다. Config::Any을 확인하십시오.

eval을 통해로드 할 데이터 구조를 만들려는 경우 (실제로 좋은 생각은 아닙니다) Data::Dumper은 피드를 생성하는 데 필요한 Perl 코드를 생성합니다. 필자가 언급 한 주된 이유는 직렬화 기보다 디버깅 도구로서 훨씬 유용하다는 것이다.

이제 파일을로드하고 (거의 모든 경우에 다시없는 좋은 생각)을 평가하려는 경우 즉, 돌봐 것을, 당신은 do 또는 require보고해야한다.

my $stuff = do 'address.pl'; 

하지만 그렇게하지 마십시오. 문자열 eval은 일반적으로 사용하지 않는 것이 가장 좋은 도구입니다. 99 %의 시간, 문자열 평가판을 사용할 계획이라면 그 문제를 해결하기 위해 다른 방법을 생각하고 그만 생각하십시오. Do는 함축적 인 평가이기 때문에 중요합니다.

Perl은 위험하고 강력한 마법을 수행하는 데 많은 도구를 제공합니다. 숙련 된 Perl 프로그래밍이되는 데는 위험한 것, 왜 그리고 언제 사용하는 것이 합리적인지 이해하는 것이 중요합니다. Perl이 울타리와 문을 지니고 아기를 안전하게 지키기를 기대하지 마십시오. 진심으로 또는 Perl Best Practices 사본을 가져 오는 것이 좋습니다. 초보자로서, 처음 읽는 동안 많은 것들이 머리 위로 떠올라지만 어느 책이든 성장하고 배우면서 훌륭한 참고 자료가 될 수 있습니다.

다음 주제에서 탈출 한 모든 인용문으로 달성하려는 것은 무엇입니까? 그것은 내 머리가 그 물건을보고 상처하게! Perl은 some very, very nice quoting operators을 사용하여 리터럴 문자열에서 이스케이프 인용 부호를 사용하는 것을 피할 수 있습니다.

=> 또는 뚱뚱한 쉼표는 영숫자 인 것처럼 자동으로 왼쪽면 (LHS)을 따옴표로 묶습니다. 그러나 모든 따옴표와 이스케이프를 넣는 것은 정말 사기스러운 일입니다.

\'address\' => {}라고 말하면 Perl은 이것을 \으로보고 문자열 참조에 "참조 얻기"연산자를 적용합니다. 이 경우 첫 번째 문자 다음에 이스케이프 처리되지 않은 '을 제공하지 않으므로 종결되지 않은 문자열 리터럴을 사용합니다. 당신의 목표는 '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이 엄청난 도움이된다는 것을 알았습니다.

나는 보통 사람을 장님이되는 충분한 텍스트 이상을 썼다. 나는이 논문이 도움이되기를 바랍니다. 환영합니다. 다시 한 번, 그리고 좋은 저녁입니다 (현지 시간이 무엇이든간에이 응답을 찾으면 조정하십시오).

관련 문제