1

分析する必要があるデータがいくつかあります。データは複数行あり、各ブロックは改行で区切られています。だから、それはこのようなものです

Property 1: 1234
Property 2: 34546
Property 3: ACBGD

Property 1: 1234
Property 4: 4567

Property 1: just
Property 3: an
Property 5: simple
Property 6: example

特定のプロパティが存在するデータ ブロックを除外する必要があります。たとえば、プロパティ 4 を持つブロックのみ、プロパティ 3 と 6 の両方を持つブロックのみなどです。これらのプロパティの値に基づいて選択する必要がある場合もあります。たとえば、プロパティ 3 とその値を持つブロックのみが 'アン。

Perlでこれを行うにはどうすればよいですか。「\n」で分割してみましたが、うまくいきません。何か不足していますか?

4

8 に答える 8

14

この作業を簡単にする秘訣は、$/ 変数を使用して Perl を「段落モード」にすることです。これにより、レコードを 1 つずつ簡単に処理できます。その後、grep などでそれらをフィルタリングできます。

#!/usr/bin/perl

use strict;
use warnings;

my @data = do {
  local $/ = '';
  <DATA>;
};

my @with_4   = grep { /^Property 4:/m } @data;

my @with_3   = grep { /^Property 3:/m } @data;
my @with_3_6 = grep { /^Property 6:/m } @with_3;

print scalar @with_3_6;

__DATA__
Property 1: 1234
Property 2: 34546
Property 3: ACBGD

Property 1: 1234
Property 4: 4567

Property 1: just
Property 3: an
Property 5: simple
Property 6: example

その例では、各レコードをプレーン テキストとして処理しています。より複雑な作業では、おそらく各レコードをハッシュに変換します。

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dumper;

my @data;

{
  local $/ = '';

  while (<DATA>) {
    chomp;

    my @rec = split /\n/;
    my %prop;
    foreach my $r (@rec) {
      my ($k, $v) = split /:\s+/, $r;
      $prop{$k} = $v;
    }

    push @data, \%prop;
  }
}

my @with_4   = grep { exists $_->{'Property 4'} } @data;

my @with_3_6 = grep { exists $_->{'Property 3'} and
                      exists $_->{'Property 6'} } @data;

my @with_3an = grep { exists $_->{'Property 3'} and
                      $_->{'Property 3'} eq 'an' } @data;

print Dumper @with_3an;

__DATA__
Property 1: 1234
Property 2: 34546
Property 3: ACBGD

Property 1: 1234
Property 4: 4567

Property 1: just
Property 3: an
Property 5: simple
Property 6: example
于 2010-11-04T09:28:52.600 に答える
3

各プロパティセットのサイズとメモリの量によって異なります...

ファイルを順番にスキャンする単純なステートマシンを使用します(複数行ではなく、行ごとの順次スキャンを使用します)。各プロパティ/ID/値をidでキー設定されたハッシュに追加します。空白行またはファイルの終わりを取得したら、ハッシュの要素をフィルターで除外するか除外するかを決定し、必要に応じてそれらを出力してから、ハッシュをリセットします。

于 2010-11-04T09:07:34.263 に答える
2
#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;

my $propertyRef;
my $propertyRefIdx = 0;

while (<>) {
    chomp($_);
    if ($_ =~ /Property (\d+): (.*)/) {
        my $propertyKey = $1;
        my $propertyValue = $2;

        $propertyRef->[$propertyRefIdx]->{$propertyKey} = $propertyValue;
    }
    else {
        $propertyRefIdx++;
    }
}

print Dumper $propertyRef;

このスクリプトが呼び出されpropertyParser.pl、 というプロパティと値を含むファイルがあるとしますproperties.txt。これは次のように呼び出すことができます。

$ propertyParser.pl < properties.txt

すべてのデータを入力$propertyRefしたら、要素をループして、特定のキーや値の組み合わせなど、適用する必要があるルールに基づいて要素をフィルタリングできます。

foreach my $property (@{$propertyRef}) {
    if (defined $property->{1} && defined $property->{3} 
                               && ! defined $property->{6}) {
        # do something for keys 1 and 3 but not 6, etc.
    }
}
于 2010-11-04T09:09:23.797 に答える
2

クイック&ダーティ:

my $string = <<END;
Property 1: 1234
Property 2: 34546
Property 3: ACBGD

Property 1: 1234
Property 4: 4567

Property 1: just
Property 3: an
Property 5: simple
Property 6: example
END

my @blocks = split /\n\n/, $string;

my @desired_blocks = grep /Property 1: 1234/, @blocks;

print join("\n----\n", @desired_blocks), "\n";
于 2010-11-04T09:11:37.180 に答える
1

レコード区切り文字は"\n\n". すべての行は 1 で終わり、2 つの改行でブロックを区別します。このアイデアを使用すると、プロパティ 4 でブロックを除外するのはかなり簡単でした。

use strict;
use warnings;
use English qw<$RS>;

open( my $inh, ... ) or die "I'm dead!";

local $RS = "\n\n";
while ( my $block = <$inh> ) { 
    if ( my ( $prop4 ) = $block =~ m/^Property 4:\s+(.*)/m ) { 
        ...
    }
    if ( my ( $prop3, $prop6 ) 
             = $block =~ m/
        ^Property \s+ 3: \s+ ([^\n]*)
        .*?
        ^Property \s+ 6: \s+ ([^\n]*)
        /smx 
       ) {
        ...
    }
}

どちらの式も複数行 ('m') フラグを使用しているため、任意^の行頭に適用されます。最後のものは、フラグを使用して「。」に改行を含めます。式 ('s') および拡張構文 ('x') など、式内の空白を無視します。

データがかなり小さい場合は、次のようにすべてを一度に処理できます。

use strict;
use warnings;
use English qw<$RS>;

local $RS = "\n\n";
my @block
    = map { { m/^Property \s+ (\d+): \s+ (.*?\S) \s+/gmx } } <DATA>
    ;
print Data::Dumper->Dump( [ \@block ], [ '*block' ] ), "\n";

結果は次のようになります。

@block = (
           {
             '1' => '1234',
             '3' => 'ACBGD',
             '2' => '34546'
           },
           {
             '4' => '4567',
             '1' => '1234'
           },
           {
             '6' => 'example',
             '1' => 'just',
             '3' => 'an',
             '5' => 'simple'
           }
         );
于 2010-11-04T15:09:50.867 に答える
0

質問の最初の部分に関連して、 perlのコマンドラインオプションを使用して「段落モード」でレコードを読み取ることができます。次に例を示します。-00

#!/usr/bin/perl -00

my @data = <>;

# Print the last block.
print $data[-1], "\n"
于 2012-01-30T10:25:07.523 に答える
0

データがファイル (mydata.txt としましょう) に保存されていると仮定すると、次の perl スクリプトを記述できます (彼を Bob.pl と呼びましょう)。

my @currentBlock = ();
my $displayCurrentBlock = 0;
# This will iterate on each line of the file
while (<>) {
  # We check the content of $_ (the current line)
  if ($_ =~ /^\s*$/) {
    # $_ is an empty line, so we display the current block if needed
    print @currentBlock if $displayCurrentBlock;
    # Current block and display status are resetted
    @currentBlock = ();
    $displayCurrentBlock = 0;
  } else{
    # $_ is not an empty line, we add it to the current block
    push @currentBlock, $_;
    # We set the display status to true if a certain condition is met
    $displayCurrentBlock = 1 if ($_ =~ /Property 3: an\s+$/);
  }
}
# A last check and print for the last block
print @currentBlock if $displayCurrentBlock;

次に、起動するだけで、出来上がりperl Bob.pl < mydata.txtです!

localhost> perl Bob.pl < mydata.txt
Property 1: just
Property 3: an
Property 5: simple
Property 6: example
于 2010-11-04T10:42:10.177 に答える
0

$/ 変数が何をするかを確認してください。たとえば、ここで説明します。「行末」セパレーターを好きなように設定できます。'\n\n' に設定してみてください

$/ = "\n\n";
foreach my $property (<DATA>)
    {
    print "$property\n";
    }


__DATA__
Property 1: 1234
Property 2: 34546
Property 3: ACBGD

Property 1: 1234
Property 4: 4567

Property 1: just
Property 3: an
Property 5: simple
Property 6: example

データ要素が空白行で区切られているように見えるため、これは行の各プロパティ グループを 1 つずつ読み取ります。

ファイル全体を配列に読み込み、メモリから処理することもできます

my(@lines) = <DATA>

于 2010-11-04T09:18:04.227 に答える