【问题标题】:Data::Dumper wraps second word's outputData::Dumper 包装第二个单词的输出
【发布时间】:2017-02-09 12:31:55
【问题描述】:

我在使用 Data::Dumper 尝试检查我是否将大量数据导入哈希时遇到了一个相当奇怪的问题。

我的数据在另一个文件中看起来像这样。

##Product ID => Market for product
ABC => Euro
XYZ => USA
PQR => India

然后在我的脚本中,我试图将我的数据列表读入像这样的哈希:

open(CONFIG_DAT_H, "<", $config_data);       
while(my $line = <CONFIG_DAT_H>) {
    if($line !~ /^\#/) {
        chomp($line);
        my @words = split(/\s*\=\>\s/, $line);
        %product_names->{$words[0]} = $words[1];
    }
}
close(CONFIG_DAT_H);
print Dumper (%product_names);

我的解析大部分都在工作,我可以在哈希中找到我的所有数据,但是当我使用 Data::Dumper 打印它时,它不能正确打印。这是我的输出。

$VAR1 = 'ABC';
';AR2 = 'Euro
$VAR3 = 'XYZ';
';AR4 = 'USA
$VAR5 = 'PQR';
';AR6 = 'India

有人知道 Dumper 为什么要打印 ';我的第二列数据的前两个字母上的字符?

【问题讨论】:

  • 在输入中看起来像回车符 (\r)。 chomp 不会摆脱它们,而是尝试像 $line =~ s/\s+$// 这样更强大的东西
  • 你需要传递一个引用,Dumper(\%product_names),而不是使用%h-&gt;{key} 语法(但%h{key})——或者——如果*product_names实际上是一个hashref,那么你需要使用正确的印记,$product_names-&gt;{key}Dumper($product_names)
  • 看起来该正则表达式有效。只是为了确保我理解它,它正在修剪任何类型的空格:\n、\r、\t 等......从行尾开始?我不知道 chomp() 没有杀死其他类型的空格。
  • 也尝试设置$Data::Dumper::Useqq = 1;
  • @mob,在所有系统上都是"\n"(除非你给它分配了别的东西)

标签: perl data-dumper


【解决方案1】:

代码中有一个不清楚的地方:*product_names 是 hash 还是 hashref?

  • 如果是hash,应该使用%product_names{key}语法,而不是%product_names-&gt;{key},并且需要传递对Data::Dumper的引用,所以Dumper(\%product_names)

  • 如果它是一个 hashref,那么它应该用正确的 sigil 标记,所以 $product_names-&gt;{key}Dumper($product_names}

正如mob 所指出的,如果您的输入有除\n 以外的任何内容,则需要更明确地清理它,例如在每条评论中使用s/\s*$//。查看ikegami的答案。

我还想补充一下,循环可以通过丢失if 分支来简化

open my $config_dat_h, "<", $config_data  or die "Can't open $config_data: $!";

while (my $line = <$config_dat_h>) 
{
    next if $line =~ /^\#/;  # or /^\s*\#/ to account for possible spaces

    # ...
}

我已更改为词法文件句柄,推荐的做法有很多优点。我还添加了对 open 的检查,它应该始终存在。

【讨论】:

  • 不幸的是,我想我不知道如何回答它是 hashref 还是 hash。两者最大的区别是什么?我一直在处理它的方式是将第一列“产品 ID”与我的第二列“市场”相关联。我看到使用 dumper 打印散列值和使用它的引用之间的最大区别是格式从打印每条数据到将它们打印到正确的列表中。
  • @JonBot 这些是不同的数据结构。如果这是您的全部代码,那么您可以决定是否希望它是一个 hashref 或一个散列 - 然后始终如一地使用它。 “hashref”是对哈希的引用,它是一个必须以$ 开头的标量。当你使用它时,你取消引用它,所以$h-&gt;{key}等。哈希以% 开头。您可以直接访问它,$h{key}。对于初学者,请参阅perlreftut。就目前而言,代码不正确。
  • @JonBot 这两者都允许您使用键值关联。 hashref 的一个更好的地方是它是一个标量,一个单一的值,对于传递给函数等要好得多。它就像 C 中的指针。但是使用它需要更多的语法。哈希的一个更好的事情是您可以直接使用数据结构,从概念上讲更容易,而且在眼睛(和手)上。当然还有更多:)
  • 我对两者的区别进行了一些研究,并在link 找到了一篇关于 SO 的相当不错的文章。我相信我想使用真正的哈希而不是 hashref。谢谢@zdim。
  • @JonBot 哦,看起来不错! (现在没能读到它。)如果你知道你想要哪个就好了!我建议你一定要了解并练习参考资料——没有参考资料,一个人就无法真正做认真的工作。
【解决方案2】:

文件使用 CR LF 作为行尾。通过将以下内容添加到您的代码中,这一点会变得很明显:

local $Data::Dumper::Useqq = 1;

您可以将文件转换为使用 unix 行尾(就像您在 unix 系统上一样)。这可以使用dos2unix 实用程序来实现。

dos2unix config.dat

或者,替换

chomp($line);

更灵活

$line =~ s/\s+\z//;

  • 注意:%product_names-&gt;{$words[0]} 没有意义。它碰巧在旧版本的 Perl 中做你想做的事,但它在新版本中正确地抛出了一个错误。 $product_names{$words[0]} 是访问散列元素值的正确语法。
  • 提示:您应该使用print Dumper(\%product_names); 而不是print Dumper(%product_names);
  • 提示:您可能还会发现local $Data::Dumper::Sortkeys = 1; 很有用。 Data::Dumper 有这么糟糕的默认值 :(
  • 提示:使用split(/\s*=&gt;\s*/, $line, 2) 代替split(/\s*=&gt;\s*/, $line) 将允许值包含=&gt;
  • 提示:您不应无缘无故地使用全局变量。使用open(my $CONFIG_DAT_H, ...) 代替open(CONFIG_DAT_H, ...),并将CONFIG_DAT_H 的其他实例替换为$CONFIG_DAT_H
  • 提示:使用next if $line =~ /^#/; 可以避免大量缩进。

【讨论】:

    【解决方案3】:

    嗯...这对我来说似乎是错误的,即使您使用的是 Perl6:

    %product_names->{$words[0]} = $words[1];
    

    我不太了解 Perl6,但在 Perl5 中,考虑到 %product_names 存在并已声明,参考应该如下所示:

    $product_names{...} = ... ;
    

    如果你能公开完整的代码,我可以帮助解决这个问题。

    【讨论】:

      猜你喜欢
      • 2011-06-26
      • 2010-09-29
      • 1970-01-01
      • 1970-01-01
      • 2010-12-08
      • 1970-01-01
      • 2016-05-23
      • 2012-06-06
      • 1970-01-01
      相关资源
      最近更新 更多