如何在Perl中将多个匹配的组作为数组的相同元素推送?

时间:2009-11-24 20:33:48

标签: perl

我需要将所有匹配的组推送到一个数组中。

#!/usr/bin/perl
use strict; 

open (FILE, "/home/user/name") || die $!;
my @lines = <FILE>;
close (FILE);
open (FH, ">>/home/user/new") || die $!;
foreach $_(@lines){
    if ($_ =~ /AB_(.+)_(.+)_(.+)_(.+)_(.+)_(.+)_(.+)_W.+txt/){
            print FH "$1 $2 $3 $4 $5 $6 $7\n"; #needs to be first element of array
    }
    elsif ($_ =~ /CD_(.+)_(.+)_(.+)_(.+)_(.+)_(.+)_W.+txt/){
            print FH "$1 $2 $3 $4 $5 $6\n"; #needs to be second element of array
    }
}close (FH);

_ INPUT _

AB_ first--2-45_ Name_ is34_ correct_ OR_ not_W3478.txt 

CD_ second_ input_ 89-is_ diffErnt_ 76-from_Wfirst6.txt

我没有将匹配的组写入FILE,而是将它们推送到数组中。我想不出push以外的任何其他命令,但是这个函数不接受多个参数。做同样的最好方法是什么?将匹配的组推入数组后,输出应如下所示。

_ OUTPUT _

$array[0] = first--2-45 Name is34 correct OR not

$array[1] = second input 89-is diffErnt 76-from

5 个答案:

答案 0 :(得分:4)

push使用的print使用相同的参数:双引号中的字符串。

push @array, "$1 $2 $3 $4 $5 $6 $7";

答案 1 :(得分:3)

查看perldoc -f grep,它会返回列表中符合某些条件的所有元素的列表。

顺便说一下,push 确实会占用多个参数:请参阅perldoc -f push

push @matches, grep { /your regex here/ } @lines;

你没有包含导致这个的代码..但有些奇怪,例如使用$_作为函数调用。你确定要这么做吗?

答案 2 :(得分:1)

如果您使用的是Perl 5.10.1或更高版本,我就会这样写它。

#!/usr/bin/perl
use strict;
use warnings;
use 5.10.1; # or use 5.010;
use autodie;

my @lines = do{
  # don't need to check for errors, because of autodie
  open( my $file, '<', '/home/user/name' );
  grep {chomp} <$file>;
  # $file is automatically closed
};

# use 3 arg form of open
open( my $file, '>>', '/home/user/new' );

my @matches;
for( @lines ){
  if( /(?:AB|CD)( (?:_[^_]+)+ )_W .+ txt/x ){
    my @match = "$1" =~ /_([^_]+)/g;
    say {$file} "@match";
    push @matches, \@match;
    # or
    # push @matches, [ "$1" =~ /_([^_]+)/g ];
    # if you don't need to print it in this loop.
  }
}

close $file;

这对输入有点宽容,但正则表达式应该比原版更“正确”。

答案 3 :(得分:0)

请记住,列表上下文中的捕获匹配会返回捕获的字段(如果有):

#!/usr/bin/perl

use strict; use warnings;

my $file = '/home/user/name';

open my $in, '<',  $file
    or die "Cannot open '$file': $!";

my @matched;

while ( <$in> ) {
    my @fields;
    if (@fields = /AB_(.+)_(.+)_(.+)_(.+)_(.+)_(.+)_(.+)_W.+txt/
            or @fields = /CD_(.+)_(.+)_(.+)_(.+)_(.+)_(.+)_W.+txt/)
    {
        push @matched, "@fields";
    }
}

use Data::Dumper;
print Dumper \@matched;

当然,您也可以

push @matched, \@fields;

取决于您打算如何处理比赛。

答案 4 :(得分:0)

我想知道使用push和巨型正则表达式是否真的是正确的方法。

OP表示他希望在索引0处以AB开头的行和在索引1处使用CD的行。 此外,那些正则表达式看起来像是一个由内而外的分裂给我。

在下面的代码中,我添加了一些教学评论,指出为什么我的做法与OP以及此处提供的其他解决方案不同。

#!/usr/bin/perl
use strict;
use warnings; # best use warnings too.  strict doesn't catch everything

my $filename = "/home/user/name";

# Using 3 argument open addresses some security issues with 2 arg open.
# Lexical filehandles are better than global filehandles, they prevent
#   most accidental filehandle name colisions, among other advantages.
# Low precedence or operator helps prevent incorrect binding of die 
#   with open's args
# Expanded error message is more helpful
open( my $inh, '<', $filename ) 
    or die "Error opening input file '$filename': $!";

my @file_data;

# Process file with a while loop.
# This is VERY important when dealing with large files.
# for will read the whole file into RAM.
# for/foreach is fine for small files.
while( my $line = <$inh> ) {
    chmop $line;

    # Simple regex captures the data type indicator and the data.
    if( $line =~ /(AB|CD)_(.*)_W.+txt/ ) {

        # Based on the type indicator we set variables 
        # used for validation and data access.

        my( $index, $required_fields ) = $1 eq 'AB' ? ( 0, 7 )
                                       : $1 eq 'CD' ? ( 1, 6 )
                                       : ();
        next unless defined $index;

        # Why use a complex regex when a simple split will do the same job?
        my @matches = split /_/, $2;

        # Here we validate the field count, since split won't check that for us.
        unless( @matches == $required_fields ) {
            warn "Incorrect field count found in line '$line'\n";
            next;
        }        

        # Warn if we have already seen a line with the same data type.
        if( defined $file_data[$index] ) {
            warn "Overwriting data at index $index: '@{$file[$index]}'\n";
        }

        # Store the data at the appropriate index.
        $file_data[$index] = \@matches;
    }
    else {
        warn "Found non-conformant line: $line\n";
    }

}

预先警告,我只需将其输入浏览器窗口即可。因此,虽然代码应该是正确的,但可能存在错别字或错过的分号潜伏 - 它未经测试,使用它自负。