在Perl中解析多行数据

在Perl中解析多行数据,perl,split,multiline,text-parsing,data-analysis,Perl,Split,Multiline,Text Parsing,Data Analysis,我有一些数据需要分析。数据是多行的,每个块由一条换行线分隔。是这样的 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的块等。我

我有一些数据需要分析。数据是多行的,每个块由一条换行线分隔。是这样的

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且其值为“an”的块


我将如何在Perl中实现这一点。我尝试用“\n”分隔它,但似乎无法正常工作。我遗漏了什么吗?

取决于每个属性集的大小和内存大小


我会使用一个简单的状态机,通过逐行顺序扫描,而不是多行顺序扫描,将每个属性/id/值添加到id上键入的哈希中。当您得到一个空行或文件结尾时,确定哈希元素是否应该被过滤进或过滤出,并根据需要发出它们,然后重置哈希。

取决于每个属性集的大小和内存大小

#!/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;
我会使用一个简单的状态机,通过逐行顺序扫描,而不是多行顺序扫描,将每个属性/id/值添加到id上键入的哈希中。当您得到一个空行或文件结尾时,确定哈希元素是否应该被过滤进或过滤出,并根据需要发出它们,然后重置散列

#!/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;
使用所有数据填充
$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.
    }
}
使用所有数据填充
$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.
    }
}
又快又脏:

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";
my$string=又快又脏:

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";

my$string=检查$/变量将为您做什么,例如解释。您可以将“行尾”分隔符设置为任意值。您可以尝试将其设置为“\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
$/=“\n\n”;
foreach my$属性()
{
打印“$property\n”;
}
__资料__
物业1:1234
物业2:34546
物业3:ACBGD
物业1:1234
物业4:4567
物业1:只是
物业3:安
属性5:简单
属性6:示例
由于您的数据元素似乎由空行去离子,这将逐个读取每个属性组的行

您还可以将整个文件读入数组并从内存中处理它


my(@lines)=

检查$/变量将为您做些什么,例如解释。您可以将“行尾”分隔符设置为任意值。您可以尝试将其设置为“\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
$/=“\n\n”;
foreach my$属性()
{
打印“$property\n”;
}
__资料__
物业1:1234
物业2:34546
物业3:ACBGD
物业1:1234
物业4:4567
物业1:只是
物业3:安
属性5:简单
属性6:示例
由于您的数据元素似乎由空行去离子,这将逐个读取每个属性组的行

您还可以将整个文件读入数组并从内存中处理它


my(@lines)=

简化此任务的秘诀是使用$/变量将Perl置于“段落模式”。这使得一次只处理一个记录变得很容易。然后你可以用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
严格使用;
使用警告;
我的@data=do{
本地$/='';
;
};
my@with_4=grep{/^Property 4:/m}@data;
my@with_3=grep{/^Property 3:/m}@data;
我的@with_3_6=grep{/^Property 6:/m}@with_3;
用_3_6打印标量@;
__资料__
物业1:1234
物业2:34546
物业3:ACBGD
物业1:1234
物业4:4567
物业1:只是
物业3:安
属性5:简单
属性6:示例
在那个示例中,我将每个记录作为纯文本处理。对于更复杂的工作,我可能会将每条记录转换为哈希

#!/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
#/usr/bin/perl
严格使用;
使用警告;
使用数据::转储程序;
我的@数据;
{
本地$/='';
而(){
咀嚼;
my@rec=split/\n/;
我的%道具;
每个我的$r(@rec){
my($k,$v)=拆分/:\s+/,$r;
$prop{$k}=$v;
}
推送@data,\%prop;
}
}
my@with_4=grep{exists$->{'Property 4'}}@data;
my@with_3_6=grep{exists$\->{'Property 3'}和
存在$\->{'Property 6'}}@data;
my@with_3an=grep{exists$\u->{'Property 3'}和
$\->{'Property 3'}eq'an'}@data;
使用_3an打印转储程序@;
__资料__
物业1:1234
物业2:34546
物业3:ACBGD
物业1:1234
物业4:4567
物业1:只是
物业3:安
属性5:简单
属性6:示例

简化此任务的秘诀是使用$/变量将Perl设置为“段落模式”。这使得一次只处理一个记录变得很容易。然后你可以用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
严格使用;
使用警告;
我的@data=do{
本地$/='';
;
};
my@with_4=grep{/^Property 4:/m}@data;
my@with_3=grep{/^Property 3:/m}@data;
我的@with_3_6=grep{/^Property 6:/m}@with_3;
用_3_6打印标量@;
__资料__
物业1:1234
物业2:34546
物业3:ACBGD
物业1:1234
物业4:4567
物业1:只是
物业3:安
属性5:简单
属性6:示例
在那个示例中,我将每个记录作为纯文本处理。对于更复杂的工作,我可能会将每条记录转换为哈希

#!/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
#/usr/bin/perl
严格使用;
使用警告;
使用数据::转储程序;
我的@数据;
{
本地$/='';
而(){
咀嚼;
my@rec=split/\n/;
我的%道具;
每个我的$r(@rec){
my($k,$v)=拆分/:\s+/,$r;
$prop{$k}=$v;
}
推送@data,\%prop;
}
}
my@with_4=grep{exists$\u->{Property
#!/usr/bin/perl -00

my @data = <>;

# Print the last block.
print $data[-1], "\n"