如何使用perl正则表达式遍历数组以查找多个模式?

时间:2012-05-25 16:17:14

标签: perl

我正在尝试在数组中找到两个模式,并将结果放入另一个数组中。

例如

  $/ = "__Data__";

  __Data__
  #SCSI_test         # put this line into  @arrayNewLines      
  kdkdkdkdkdkdkdkd
  dkdkdkdkdkdkdkdkd
  - ccccccccccccccc  # put this line into @arrayNewLines

代码

    while(<FILEREAD>)
    {
          chomp;
          my @arrayOld = split(\n,@array);

          foreach my $i (0 .. $#arrayOld)
          {
                if($arrayOld[$i] =~ /^-(.*)/g or /\#(.*)/g)
                {
                     my @arrayNewLines = $arrayOld[$i];
                     print "@arrayNewLines\n";
                }
          }
    }

此代码仅打印出ccccccccccccccc 但是我想输出ccccccccccccccc #SCSI_test

2 个答案:

答案 0 :(得分:1)

该代码不仅仅打印cccccc...,它会打印所有内容。你的问题就在这一行:

if($arrayOld[$i] =~ /^-(.*)/g or /\#(.*)/g) {

您在此处执行的操作是首先检查$arrayOld[$i],然后选中$_,因为/\#(.*)/$_ =~ /\#(.*)/的perl简写。由于该行包含散列字符#,因此它将始终匹配,并且该行将始终打印。

您的行等同于:

if(   $arrayOld[$i] =~ /^-(.*)/g 
      or 
      $_ =~ /\#(.*)/g) {

答案是加入正则表达式:

if($arrayOld[$i] =~ /^-|#/) {

然而,之后您的代码远非干净......从顶部开始:

如果您使用该输入将输入记录分隔符$/设置为__Data__,您将获得两条记录(Data::Dumper输出如下所示):

$VAR1 = '__Data__';
$VAR1 = '
#SCSI_test         # put this line into  @arrayNewLines
kdkdkdkdkdkdkdkd
dkdkdkdkdkdkdkdkd
- ccccccccccccccc  # put this line into @arrayNewLines
';

当您chomp记录时,您将从结尾删除__Data__,因此第一行将变为空。所以从本质上讲,你总是会有一个领先的空场。这并不可怕,但要记住一些事情。

您的split声明错误。首先,第一个参数应该是正则表达式:/\n/。第二个参数应该是标量,而不是数组。 split(/\n/,@array)将评估为split(/\n/, 2),因为数组位于标量上下文中并返回其大小而不是其元素。

当然,由于您处于FILEREAD句柄的循环读取行中,因此@array数组将始终包含相同的数据,并且与文件中的数据无关处理。你想要的是:split /\n/, $_

这个循环:

foreach my $i (0 .. $#arrayOld) {
对于这个问题,

不是一个非常好的循环结构。而且,不需要使用中间阵列。只需使用:

for my $line (split /\n/, $_) {

当你这样做时

my @arrayNewLines = $arrayOld[$i];
print "@arrayNewLines\n";

您正在将整个数组设置为标量,然后打印它,这是完全冗余的。只是直接打印标量就可以获得相同的效果。

您的代码应如下所示:

while(<FILEREAD>) {
    chomp;
    foreach my $line (split /\n/, $_) {
        if($line =~ /^-|#/) {
            print "$line\n";
        }
    }
}

还建议您使用词法文件句柄,而不是

open FILEREAD, "somefile" or die $!;       # read with <FILEREAD>

使用:

open my $fh, "<", "somefile" or die $!;    # read with <$fh>

答案 1 :(得分:0)

#! /usr/bin/env perl

use strict;
use warnings;

*ARGV = *DATA;

my @arrayNewLines;

while (<>) {
  chomp;

  if (/^-(.*)/ || /\#(.*)/) {
    push @arrayNewLines, $_;
  }
}

print "$_\n" for @arrayNewLines;

__DATA__
#SCSI_test         # put this line into  @arrayNewLines
kdkdkdkdkdkdkdkd
dkdkdkdkdkdkdkdkd
- ccccccccccccccc  # put this line into @arrayNewLines

更好的是,如果你有5.10或更新,请使用智能匹配。

#! /usr/bin/env perl

use strict;
use warnings;

use 5.10.0;  # for smart matching

*ARGV = *DATA;

my @arrayNewLines;

my @patterns = (qr/^-(.*)/, qr/\#(.*)/);

while (<>) {
  chomp;
  push @arrayNewLines, $_ if $_ ~~ @patterns;
}

print "$_\n" for @arrayNewLines;

__DATA__
#SCSI_test         # put this line into  @arrayNewLines
kdkdkdkdkdkdkdkd
dkdkdkdkdkdkdkdkd
- ccccccccccccccc  # put this line into @arrayNewLines

无论哪种方式,输出都是

#SCSI_test         # put this line into  @arrayNewLines
- ccccccccccccccc  # put this line into @arrayNewLines