我有以下散列:
my %MacroA = ('Category' => {}, 'Item' => {}, 'Description' => {}, 'Score' => {});
我想要的是循环浏览一个文件,然后在不同的散列中添加新元素。假设这行包含"布局",我想每次看到时都将其存储在"类别"中
我所做的是:
while (my $line = <$file>) {
if ($line =~ /b(layout)b,/) {
foreach my $categories (keys $MacroA{'Category'}) {
$MacroA{Category} = $1;
}
}
您的问题被问得很困惑,但您的问题似乎是因为您对引用而不是哈希执行keys
。较新的perl确实支持此功能,但您可能使用的是较旧的版本。
在您的示例中,$MacroA{'Category'}
返回散列引用,而不是散列。您使用'Category' => {}
初始化了哈希,{}
是对空匿名哈希的引用。
要将散列引用转换为散列,可以使用%{ ... }
表示法;在这种情况下,您将编写keys %{ $MacroA{'Category'} }
。是的,这很难看,这就是为什么Perl在引用中被更改为支持keys
的原因。
但是请注意,您的下一行是$MacroA{Category} = $1;
,它将用$1
中的任何内容替换引用,可能是字符串"layout"
。这不是一个参考,所以下次循环时,你的脚本会崩溃。你可能想做一个多级散列,比如$MacroA{Category}{$1} = $file
之类的,这取决于你想在散列中建立什么数据,但你想实现什么并不清楚。另一个建议数组散列的答案可能正是您想要的。在这种情况下,如果使用较旧的perl,则符号@{ ... }
将数组引用转换为可以与push
一起使用的数组。
在这里,您似乎正在尝试做一种命名列的事情。这是非常直接,如果你知道怎么做的话。
从你的评论到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*layoutb/;
$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*layoutb/;
$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
;
下面是一个完整的程序,分为不同的块。要运行它,请将答案复制并粘贴到名为populate
的文件中,但要删除注释部分,如此段落。
几乎所有Perl程序(尤其是当您还是初学者时)都应该从开始
#! /usr/bin/env perl
use strict;
use warnings;
第一行告诉系统如何执行程序。启用strict
和warnings
杂注将有助于避免常见错误,并有助于解释程序在出现意外行为时所做的操作。
根据你的问题,你想要的数据结构是一个散列数组。数组的每个"行"或元素将对应于输入文件中的一行,并具有形式
# { Category => '...', Item => '...', Description => '...', Score => '...' }
程序还将从输入中读取列名。
该代码使用Perl的"菱形运算符"来读取每一行输入。chomp
删除尾部换行符(如果存在)。
如果行告诉我们标题名称(即,它从#
开始),我们将每个字段存储在@columns
中。ucfirst
位可能不熟悉:它upperc是字符串的第一个字符。因为有几个列名,所以我们使用map
将ucfirst
应用于每个列名。
否则,该行表示一个数据行。我们将该行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;
}
}
请注意,上面的拆分是naïaut;ve。要处理一般CSV输入,请使用CPAN上的CSV模块之一。
Data::Dumper模块可用于快速打印复杂数据结构的内容。把它放在调试工具包里。
use Data::Dumper;
$Data::Dumper::Indent = $Data::Dumper::Terse = 1;
print Dumper @MacroA;
__END__
给定内容低于的文件input
#category,item,description,score布局,f.4,宏放置间隙,通道布局,f.14,无区域拥堵,通行布局,f.17,放置套环二极管,故障布局,f.18,放置轴环缓冲,通道布局,f.26,连接,故障布局,f.28,CTS允许的小区,失败布局,f.29,CTS允许分层,通过布局,f.31,时钟去帽单元,失败layout,f.33,Clock非默认规则,fail
下面是一个示例运行。
$perl填充输入[{"得分"=>"通过",'项目'=>'f.4',"说明"=>"宏放置间隙","类别"=>"布局"},{"得分"=>"通过",'项目'=>'f.14','描述'=>'无区域拥堵',"类别"=>"布局"},{"得分"=>"失败",'项目'=>'f.17',"说明"=>"放置套环二极管","类别"=>"布局"},{"得分"=>"通过",'项目'=>'f.18',"描述"=>"放置项圈缓冲区","类别"=>"布局"},{"得分"=>"失败",'项目'=>'f.26',"描述"=>"连接","类别"=>"布局"},{"得分"=>"失败",'项目'=>'f.28','描述'=>'允许CTS的小区',"类别"=>"布局"},{"得分"=>"通过",'项目'=>'f.29','描述'=>'允许CTS分层',"类别"=>"布局"},{"得分"=>"失败",'项目'=>'f.31','描述'=>'时钟去帽单元',"类别"=>"布局"},{"得分"=>"失败",'项目'=>'f.33','描述'=>'时钟非默认规则',"类别"=>"布局"}]
我认为您需要一个数组哈希:
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;
}
}
您的问题令人困惑。只需在Category键中添加"layout"很简单,不涉及循环:
while (my $line = <$file>) {
if ($line =~ /blayoutb,/) {
$MacroA{Category} = 'layout';
}
}