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

问题描述 投票:0回答:2

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

例如

  $/ = "__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

regex perl
2个回答
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>

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 # 将此行放入@arrayNewLines
- ccccccccccccccc #将此行放入@arrayNewLines
© www.soinside.com 2019 - 2024. All rights reserved.