【问题标题】:Perl eval Data::Dumper inconsistencyPerl eval Data::Dumper 不一致
【发布时间】:2016-03-28 11:19:39
【问题描述】:

我必须在 Perl 中进行序列化和反序列化。我知道Data::Dumpereval 不是最适合这项工作的,但我不允许在我正在处理的旧脚本中修改这方面。
以下是使用eval 的两种方式(CODE 1CODE 2)。
CODE 1 中,哈希值在通过 eval 反序列化之前以字符串形式提供。
CODE 2 中,哈希使用Dumper 进行序列化,然后通过eval 进行反序列化。

在这两个代码示例中,两种尝试反序列化的方法之一都有效。为什么其他反序列化方法不起作用?

代码 1

my $r2 = "( 
'w' => {
           'k2' => 5,
           'k1' => 'key',
           'k3' => [
                     'a',
                     'b',
                     2,
                     '3'
                   ]
         },
  'q' => 2 
)"; 

my %z; 
eval "\%z = $r2";          ####### Works. 
print "\%z = [".Data::Dumper::Dumper (\%z)."] "; 

my $answer = eval "$r2";   #### Does NOT work. 
print "\n\nEvaled = [".Dumper($answer)."] "; 

输出

%z = [$VAR1 = {
          'w' => {
                   'k2' => 5,
                   'k1' => 'key',
                   'k3' => [
                             'a',
                             'b',
                             2,
                             '3'
                           ]
                 },
          'q' => 2
        };
]

Evaled = [$VAR1 = 2;
]

但下面的代码以相反的方式工作:
CODE 2

my %a = ( "q" =>2, "w"=>{ "k1"=>"key", "k2"=>5, k3=>["a", "b", 2, "3",], }, );  **# Same hash as above example.** 
$Data::Dumper::Terse=1; 
$Data::Dumper::Purity = 1; 
my $r2 = Dumper(\%a); 

my %z; 
eval '\%z = $r2'; 
print "\n\n\%z = [".Dumper(\%z)."] ";         #### Does NOT work. 

my $answer = eval $r2; 
print "\n\nEvaled = [".Dumper($answer)."] ";  ####### Works.

输出

%z = [$VAR1 = {};
]

Evaled = [$VAR1 = {
          'w' => {
                   'k2' => 5,
                   'k1' => 'key',
                   'k3' => [
                             'a',
                             'b',
                             2,
                             '3'
                           ]
                 },
          'q' => 2
        };
]

【问题讨论】:

    标签: perl serialization deserialization eval data-dumper


    【解决方案1】:

    首先,请不要放置导致语法错误的cmets (**)。

    请注意,您在第一个代码块中提供的字符串产生的数据结构与 Dumper 函数不同。在第一个块中,您正在创建一个哈希,但您没有将它分配给任何变量。对于 Dumper 函数,会创建匿名哈希,并将其引用传递给 $VAR 变量。

    要使第一个代码工作,您应该将( 替换为{ 以创建匿名哈希,然后将其分配给变量,例如:

    my $r2 = "$VAR = { 
        'w' => {
               'k2' => 5,
               'k1' => 'key',
               'k3' => [
                         'a',
                         'b',
                         2,
                         '3'
                       ]
             },
      'q' => 2 
    }"; 
    

    【讨论】:

    • 感谢您的宝贵时间。目前,我正在使用模式匹配和替换来用圆括号更改前导和尾随花括号。我们也可以用其他方式来做吗?另外,我已经删除了星星。我应该把它们放在#后面。
    • 您不需要更改所有数据。只需改变你做作业的方式。
    【解决方案2】:

    不要使用 Data::Dumper 来序列化数据。说了这么多……

    这是一个标量和列表上下文的问题。在第二个评估中,您有:

    my $answer = ...;
    

    由于您分配给标量,因此在标量上下文中评估右侧。这意味着 eval 在标量上下文中。该值是:

    (
    'w' => {
               'k2' => 5,
               'k1' => 'key',
               'k3' => [
                         'a',
                         'b',
                         2,
                         '3'
                       ]
             },
      'q' => 2
    )
    

    这看起来像一个列表,但它实际上是标量上下文中的逗号运算符。评估左侧,丢弃该结果并返回右侧。所以,my $x = ( 'left', 'right' )right 分配给$x。这在What is the difference between a list and an array? 中的perlfaq4 中有介绍。

    在您的问题中,您看到$r 获得了值2。这是逗号链中最右边的值,所以这就是您在标量上下文中返回的值。将其更改为另一个值(可能是'duck'),这就是您将获得的值:

    my $r2 = "(
        'w' => {
                   'k2' => 5,
                 },
          'q' => 'duck'
        )";
    
    my $answer = eval "$r2";
    
    use Data::Dumper;
    print "Evaled =\n" . Dumper($answer);
    

    这不是一个数字,这让人们感到困惑,因为他们认为这是某种计数:

    Evaled =
    $VAR1 = 'duck';
    

    将其更改为在列表上下文中分配(哈希分配是列表分配),您会得到正确答案:

    my $r2 = "(
        'w' => {
                   'k2' => 5,
                 },
          'q' => 'duck'
        )";
    
    my @answer = eval "$r2";
    
    use Data::Dumper;
    print "Evaled =\n" . Dumper(\@answer);
    

    现在是您认为应该是的数据结构:

    Evaled =
    $VAR1 = [
              'w',
              {
                'k2' => 5
              },
              'q',
              'duck'
            ];
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-26
      • 2014-11-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多