在 Perl 中包含哈希值内的哈希值

发布于 2024-10-14 01:45:45 字数 1666 浏览 1 评论 0原文

你好,

我目前正在努力从许多较小的哈希值创建大哈希值。假设这些较小的哈希值各自定义在一个文件中,然后可以包含在较大的哈希值中。

例如,让我们看一些小哈希

文件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\'
        }
    } 

我已经得到了相当多的这些......

我的方式我尝试使用 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: $@") if $@;
close($fh) or die("FILECLOSE: $!");
return $result;
 }

我知道我一定做错了什么,但我不确定是什么。我不断收到类似 Useless use of a variable in void context at (eval 11) line 4,的错误第 6 行第 5 行(eval 11)处匿名哈希中的奇数元素,第 6 行。我不知道如何找到 (eval 11) 第 4-3 行、第 6 行。任何关于使用 Perl 调试器的建议或任何关于我可能出错的地方的指示将不胜感激。

谢谢!

G'Day,

I'm currently working on creating big hashes from a lot of smaller hashes. Let's say that these smaller hashes are defined in a file each, and then can be included by the bigger hash.

For eg, let's look at some small hashes

File personcontact.pl:

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

File 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\'
        }
    } 

And I've got a considerable number of these...

The way I'm trying to re-create the hash is using the include subroutine, which looks like this:

 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: $@") if $@;
close($fh) or die("FILECLOSE: $!");
return $result;
 }

I know I must be doing something wrong, but I'm not sure what. I keep on getting errors like Useless use of a variable in void context at (eval 11) line 4, <SCHEMAFILE> line 6 or Odd number of elements in anonymous hash at (eval 11) line 5, <SCHEMAFILE> line 6. I'm not sure how to go about finding (eval 11) line 4-3, line 6 though. Any suggestions on use of Perl debuggers or any pointers on where I might be going wrong will be much appreciated.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

东风软 2024-10-21 01:45:45

欢迎来到 Perl。我希望您学习和使用它愉快。

谈生意,从哪里开始?在这里我有很多话要说。

首先,通过评估文件加载数据存在不必要的风险。如果您只想序列化数据,请尝试 JSON::XSYAML,甚至 可存储。如果您需要配置文件,CPAN 上有很多很多模块可以帮助完成此任务。查看 Config::Any

如果您想创建通过 eval 加载的数据结构(这并不是一个好主意),数据: :Dumper 生成创建您提供给它的任何数据结构所需的 Perl 代码。我提到它的主要原因是它作为调试辅助工具比序列化器有用得多。

既然已经解决了这个问题,如果您想加载文件并对其进行评估(同样,这并不是在几乎所有情况下都是最好的主意),您应该查看 do要求

my $stuff = do 'address.pl';

但不要这样做。字符串 eval 是一个通常最好不使用的工具。 99% 的情况下,如果您计划使用字符串 eval,请停止并考虑另一种方法来解决问题。 Do 是一个隐式的 eval,所以它也很重要。

Perl 为您提供了许多工具来实现危险而强大的魔法。成为一名熟练的 Perl 编程人员的很大一部分在于了解哪些事情是有风险的、为什么以及何时使用它们是有意义的。不要指望 Perl 会用栅栏和大门来保护你,以保证你的安全。认真考虑购买一本Effective Perl 编程Perl 最佳实践。作为新手,第一次阅读时可能会遇到很多问题,但随着您的成长和学习,这两本书都可以成为很好的参考。

下一个主题,您到底想通过所有这些转义引号实现什么目的?看到那些东西我就头疼! Perl 有一些非常非常好的引用运算符,您可以使用它们可以用来避免在文字字符串中使用转义引号。

=> 或粗逗号自动引用其左侧 (LHS),就好像它只是字母数字一样。但加上所有的引号和转义符会让事情变得非常危险。

当你说 \'address\' =>; {},Perl 将其视为 \,即应用于字符串文字的“获取引用”运算符。在这种情况下,是一个未终止的字符串文字,因为您永远不会在第一个字符串之后提供未转义的 '

如果您的目标是使用 'address'、引号和所有内容作为哈希键,您可以执行以下操作:

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

如果您不需要引号(这似乎是更常见的用例),只需执行以下操作:

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

关于您收到的错误消息!一旦您了解了 Perl 的全部含义,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 数据结构手册数组的数组教程。作为初学者,我发现 perlfunc 的 Perl 函数按类别部分非常有帮助。

我想我会停下来,因为我已经写了足够多的文字来蒙蔽普通人。我希望这篇论文对您有所帮助。再次欢迎,晚上好(请调整到您发现此回复时的当地时间)。

Welcome to Perl. I hope you have a good time learning and using it.

On to business, where to start? I've got a lot to say here.

First off, it's unnecessarily risky to load data by evaluating files. If you just want to serialize data try JSON::XS or YAML, or even Storable. If you want a config file, there are many, many modules on CPAN that help with this task. Check out Config::Any.

If you want to create data structures to load via eval (which is not really a good idea), Data::Dumper generates perl code needed to create any data structures you feed to it. The main reason I mention it is that it is far more useful as a debugging aid than a serializer.

Now that that is taken care of, if you want to load a file and evaluate it (again, not the best idea in nearly every case), you should be looking at do or require.

my $stuff = do 'address.pl';

But don't do that. String eval is a tool that is generally best left unused. 99% of the time, if you are planning on using string eval, stop and think of another way to solve the problem. Do is an implicit eval, so it counts too.

Perl gives you lots of tools to do risky and powerful magic. A large part of becoming a skilled Perl programming lies in understanding what things are risky, why and when it makes sense to use them. Don't expect Perl to baby you with fences and gates to keep you safe. Seriously consider picking up a copy of Effective Perl Programming or Perl Best Practices. As a newbie, much will go over your head as you read the first time, but either book can be a great reference as you grow and learn.

Next topic, what in the world are you trying to achieve with all those escaped quotes? It makes my head hurt to look at that stuff! Perl has some very, very nice quoting operators that you can use to avoid ever having to mess around with escaping quotes in your literal strings.

The => or fat comma automatically quotes its left hand side (LHS) as if it is alphanumerics only. But putting all the quotes and escapes makes things really dodgy.

When you say \'address\' => {}, Perl sees this as the \, the "get reference" operator applied to a string literal. In this case, an unterminated string literal, because you never offer an unescaped ' after the first.

If your aim is to use 'address', quotes and all as your hash key, you can do this:

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

If you don't want the quotes, which seems a far more usual use case, simply do:

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

On to the error messages you were getting! Perl has some pretty nice error messages once you learn what they all mean. Until then, it can be a bit tough to understand their significance. Fortunately Perl ships with a script called splain: a handy dandy tool that will explain error messages in much greater detail. You can also use the diagnostics module to get the same, expanded error messages automatically.

Now, if I was writing this I'd do something along these lines:

gen_schema_files.pl - A file to write JSON schema files. You could hand edit your schemata if you want to. You may also want to configure the output to be prettier if you want to improve readability.

#!/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 - this is the code that loads the schemata and does stuff. Mine only gets loaded. I have no idea what you are doing with the data...

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

I've glossed over a few things, but I've tried to leave comments with enough of the terms (vocabulary or even jargon, if you like) to allow you to do profitable searches.

The above code has a couple flaws. It does not do any checking for circular inclusions (it will run for a long time and eventually fill up memory and crash--not so good). The choice of magic key may not be good. And there are probably more I haven't even thought of yet.

Perldoc is an amazing resource, but there is so much there that it takes a while to learn to find things. Take a look at the Perl Data Structures Cookbook and the Arrays of Arrays tutorial. As a beginner, I found the Perl Functions by Category section of perlfunc to be incredibly helpful.

I think I'll stop, now that I've written more than enough text to blind the average person. I hope you find this dissertation helpful. Welcome, once again, and good evening (please adjust to whatever your local time is when you find this response).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文