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;あるものに置き換えることに注意してください。これは参照ではないので、次にwhileループを回るときに、スクリプトがキールオーバーします。ハッシュに蓄積したいデータに応じて、マルチレベルのハッシュなどを実行したいと思うかもしれませんが、何を達成しようとしているのかは明確ではありません。配列のハッシュを示唆する他の答えはあなたが望むものかもしれません。この場合、古いperlを使用している場合、表記は配列参照をで使用できる配列に変換します。$1"layout"$MacroA{Category}{$1} = $file@{ ... }push

于 2012-11-28T12:22:49.913 に答える
2

ここでは、ある種の名前付き列を実行しようとしているようです。あなたがそれを行う方法を知っていれば、これはかなり簡単です。

コメントからPeterに移動すると(「[I]各行の「レイアウト」を「説明」に保存したい」)、このコードで実行できるのは、保存することです。

ハッシュについて私が目にする主なケースはレコード自体であるため、このデモンストレーションで使用するハッシュはそれだけです。それらを配列に格納します。私はあなたがあなたの例からそれらをどのように索引付けしたいかを本当に理解していません。そして、あなたはそれらをどのように処理したいかについて少し混乱しているようです。確かに、を含むすべての行を処理し '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

あなたの質問は紛らわしいです。カテゴリキーに「レイアウト」を追加するだけで簡単で、ループは発生しません。

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;

最初の行は、プログラムの実行方法をシステムに指示します。strictand pragmataを有効にするとwarnings、よくある間違いを回避し、驚くべき動作が見られる場合にプログラムが何をしているかを説明するのに役立ちます。

あなたの質問に基づいて、あなたが望むデータ構造はハッシュの配列です。配列の各「行」または要素は、入力ファイルの行に対応し、次の形式になります。

# { 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モジュールの1つを使用します。

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、セルのキャップ解除のクロック、失敗
レイアウト、f.33、時計以外のデフォルトルール、失敗

サンプルの実行は以下のとおりです。

$perlは入力を入力します
[
  {{
    'スコア'=>'合格'、
    'アイテム'=>'f.4'、
    '説明'=>'マクロ配置クリアランス'、
    'カテゴリ'=>'レイアウト'
  }、
  {{
    'スコア'=>'合格'、
    'アイテム'=>'f.14'、
    '説明'=>'エリアの混雑なし'、
    'カテゴリ'=>'レイアウト'
  }、
  {{
    'スコア'=>'失敗'、
    'アイテム'=>'f.17'、
    '説明'=>'配置カラーダイオード'、
    'カテゴリ'=>'レイアウト'
  }、
  {{
    'スコア'=>'合格'、
    'アイテム'=>'f.18'、
    '説明'=>'配置カラーバッファー'、
    'カテゴリ'=>'レイアウト'
  }、
  {{
    'スコア'=>'失敗'、
    'アイテム'=>'f.26'、
    '説明'=>'タイ接続'、
    'カテゴリ'=>'レイアウト'
  }、
  {{
    'スコア'=>'失敗'、
    'アイテム'=>'f.28'、
    '説明'=>'CTS許可セル'、
    'カテゴリ'=>'レイアウト'
  }、
  {{
    'スコア'=>'合格'、
    'アイテム'=>'f.29'、
    '説明'=>'CTSの敷設が許可されました'、
    'カテゴリ'=>'レイアウト'
  }、
  {{
    'スコア'=>'失敗'、
    'アイテム'=>'f.31'、
    '説明'=>'クロックデキャップセル'、
    'カテゴリ'=>'レイアウト'
  }、
  {{
    'スコア'=>'失敗'、
    'アイテム'=>'f.33'、
    '説明'=>'時計以外のデフォルトルール'、
    'カテゴリ'=>'レイアウト'
  }
]
于 2012-11-28T17:04:22.383 に答える