3

我有以下哈希值:

my %MacroA = ('Category' => {}, 'Item' => {}, 'Description' => {}, 'Score' => {});

我想要的是遍历一个文件,然后将新元素添加到不同的哈希中。假设该行包含“布局”,我每次看到它时都想将其存储在“类别”中

我所做的是:

while (my $line = <$file>) {                                        

if ($line =~ /\b(layout)\b,/) { 
foreach my $categories (keys $MacroA{'Category'}) {
    $MacroA{Category} = $1;
}
}
4

5 回答 5

3

您的问题非常令人困惑,但您的问题似乎是因为您正在keys参考而不是哈希。较新的 perls 确实支持这一点,但您可能使用的是旧版本。

在您的示例中$MacroA{'Category'}返回哈希引用,而不是哈希。您使用 , 初始化了散列'Category' => {},并且{}是对空匿名散列的引用。

要将散列引用转换为散列,请使用%{ ... }符号;在这种情况下,你会写keys %{ $MacroA{'Category'} }. 是的,这很难看,这就是为什么 Perl 被更改为支持keys引用。

但是请注意,您的下一行是$MacroA{Category} = $1;将引用替换为 中的任何内容$1,可能是字符串"layout"。这不是参考,所以下一次 while 循环时,你的脚本会崩溃。您可能想要做一个多级哈希,类似$MacroA{Category}{$1} = $file或类似的东西,这取决于您想要在哈希中建立什么数据,但目前还不清楚您想要实现什么。另一个建议散列数组的答案可能是您想要的。在这种情况下,如果使用较旧的 perl,则符号@{ ... }会将数组引用转换为可以与 一起使用的数组push

于 2012-11-28T12:22:49.913 回答
2

看起来你正在尝试做一种命名列的事情,在这里。这很简单,如果你知道怎么做的话。

从您对 Peter 的评论开始(“[我] 想要将每一行的“布局”存储到“描述”),这就是这段代码允许你做的事情:存储它。

因为我看到的散列的主要情况是记录本身,所以这是该演示使用的唯一散列。它将它们存储在一个数组中。我真的不明白你想如何从你的例子中索引它们。而且您似乎对如何处理它们有些困惑。'layout'当然,处理其中包含的每一行然后将其存储为“类别”字段并不是很有用 。

use strict;
use warnings;

my @columns = qw<field1 field2 field3 field4>;
my @list;
my $fh = \*::DATA;
my $header = <$fh>;
if ( substr( $header, 0, 1 ) eq '#' ) {
    ( $header ) = $header =~ m/#(.*)/;
    $header =~ s/\s+$//; 
    @columns = split /,\s*/, $header;
}
else { 
    seek( $fh, 0, 0 ); # go back
}

# optional statement to capitalize field names
@columns = map { ucfirst } @columns;

while ( my $line = <$fh> ) { 
    next unless $line =~ m/^\s*layout\b/;
    $line =~ s/\s*$//;
    # store fields by hash slice in the tip of the array
    @{ $list[@list] }{ @columns } = split /,\s*/, $line;
}

__DATA__
#category, item, description, score 
layout,f.4,Macro placement clearance,pass 
layout,f.14,No area congestion,pass 
layout,f.17,placement collar diode,fail 
layout,f.18,placement collar buffer,pass 
layout,f.26,tie connection,fail 
layout,f.28,CTS allowed cell,fail 
layout,f.29,CTS allowed layed,pass 
layout,f.31,Clock De-cap cell,fail 
layout,f.33,Clock non default rule,fail

虽然它不是你想要的一切,但将记录复制到数组中是“处理它”的简单模型,我们可以这样做:

my %by_item;
while ( my $line = <$fh> ) { 
    next unless $line =~ m/^\s*layout\b/;
    $line =~ s/\s*$//;
    my %h;
    @h{ @columns } = split /,\s*/, $line;
    $by_item{ $h{Item} } = \%h;
    ### OR 
    # push @{ $by_item{ $h{Item} } }, %h;
}

你也可以这样做:

my %by_field;
...
$by_field{Item}{ $h{Item} }               
    = $by_field{Description}{ $h{Description} } 
    = \%h
    ;
于 2012-11-28T14:40:29.767 回答
1

我认为您需要一个数组散列:

my %MacroA = ('Category' => [], 'Item' => [], 'Description' => [], 'Score' => []);

while (my $line = <$file>) {                                        

if ($line =~ /\b(layout)\b,/) { 
foreach my $categories (keys $MacroA{'Category'}) {
    push $MacroA{Category}, $1;
}
}
于 2012-11-28T12:20:33.160 回答
1

你的问题令人困惑。只需将“布局”添加到 Category 键很简单,不涉及循环:

while (my $line = <$file>) {                                        
    if ($line =~ /\blayout\b,/) { 
        $MacroA{Category} = 'layout';
    }
}
于 2012-11-28T12:26:55.340 回答
1

下面是一个完整的程序,分成不同的块。要运行它,请将答案复制并粘贴到名为 的文件populate中,但要删除本段等注释部分。

几乎所有 Perl 程序(尤其是当您还是初学者时)都应该从

#! /usr/bin/env perl

use strict;
use warnings;

第一行告诉系统如何执行你的程序。启用strictwarningspragmata 将帮助您避免常见错误,并帮助解释您的程序在您看到令人惊讶的行为的情况下正在做什么。

根据您的问题,您想要的数据结构是哈希数组。数组的每个“行”或元素将对应于输入文件中的一行,并具有以下形式

# { Category => '...', Item => '...', Description => '...', Score => '...' }

该程序还将从输入中读取列名。

该代码使用 Perl 的“菱形运算符”来读取每一行输入。chomp如果存在,则删除尾随换行符。

如果该行告诉我们标题名称(,它以 开头#),我们将每个字段存储在@columns. 该ucfirst位可能不熟悉:它是字符串第一个字符。因为有几个列名,我们使用来应用到每一个。mapucfirst

否则,该线代表一个数据行。我们split将行插入以逗号分隔的字段并将它们加载到新的哈希中。该push行将引用(在哈希之前使用反斜杠创建)添加到@MacroA.

my @MacroA;
my @columns;
while (<>) {
  chomp;

  if (s/^#//) {                               # / fix Stack Overflow coloring
    @columns = map ucfirst, split /\s*,\s*/;  # / ditto
  }
  else {
    my %row;
    @row{@columns} = split /,/;
    push @MacroA, \%row;
  }
}

请注意,上面的拆分是天真的。要处理一般 CSV 输入,请使用CPAN 上的 CSV 模块之一。

Data::Dumper模块可用于快速打印复杂数据结构的内容。把它放在你的调试工具包里。

use Data::Dumper;
$Data::Dumper::Indent = $Data::Dumper::Terse = 1;
print Dumper \@MacroA;

__END__

input给定一个包含以下内容的文件

#category, item, description, score
layout,f.4,宏放置间隙,pass
布局,f.14,无区域拥堵,通过
布局,f.17,放置领二极管,失败
布局,f.18,放置领缓冲区,通过
布局,f.26,领带连接,失败
布局,f.28,CTS 允许单元格,失败
布局,f.29,CTS 允许铺设,通过
布局,f.31,时钟去电容单元,失败
布局,f.33,时钟非默认规则,失败

下面是一个示例运行。

$ perl 填充输入
[
  {
    '分数' => '通过',
    '项目' => 'f.4',
    '描述' => '宏放置间隙',
    '类别' => '布局'
  },
  {
    '分数' => '通过',
    '项目' => 'f.14',
    '描述' => '没有区域拥堵',
    '类别' => '布局'
  },
  {
    '得分' => '失败',
    '项目' => 'f.17',
    '描述' => '安置领二极管',
    '类别' => '布局'
  },
  {
    '分数' => '通过',
    '项目' => 'f.18',
    '描述' => '放置领缓冲区',
    '类别' => '布局'
  },
  {
    '得分' => '失败',
    '项目' => 'f.26',
    '描述' => '领带连接',
    '类别' => '布局'
  },
  {
    '得分' => '失败',
    '项目' => 'f.28',
    '描述' => 'CTS 允许的单元格',
    '类别' => '布局'
  },
  {
    '分数' => '通过',
    '项目' => 'f.29',
    '描述' => 'CTS 允许铺设',
    '类别' => '布局'
  },
  {
    '得分' => '失败',
    '项目' => 'f.31',
    'Description' => 'Clock De-cap cell',
    '类别' => '布局'
  },
  {
    '得分' => '失败',
    '项目' => 'f.33',
    '描述' => '时钟非默认规则',
    '类别' => '布局'
  }
]
于 2012-11-28T17:04:22.383 回答