Perl - 将正则表达式中的行推入数组的一个元素

时间:2017-03-02 19:52:41

标签: arrays perl split

这是我正在处理的日志文件 -

|
blah1a
blah1b
blah1c
|
****blahnothing1
|
blah2a
blah2b
blah2c
|
blahnothing2
|
blah3a
blah3b
blah3c
|
blahnothing3

我需要的信息位于两个管道字符之间。从asteriks开始有很多行,我跳过它们。每行都有windows行尾字符。这些管道字符之间的数据是有余的,但是当在linux主机上读取时,它会被windows新行切断。 我在两行之间编写了一个带有范围运算符的perl脚本,希望以管道分隔符开头的所有内容都会被推入数组元素,然后停在下一个管道分隔符,然后重新开始。每个数组元素都包含两个管道字符之间的所有行。

理想情况下,数组看起来像这样,没有Windows控件字符。

$lines[0] blah1a blah1b blah1c
$lines[1] blah2a blah2b blah2c
$lines[2] blah3a blah3b blah3c

但是每个阵列看起来都不一样。

#!/usr/bin/perl

use strict ;
use warnings ;

my $delimiter = "|";
my $filename = $ARGV[0] ;
my @lines ;
open(my $fh, '<:encoding(UTF-8)' , $filename) or die "could not open file $filename $!";

while (my $line = readline $fh) {
    next if ($line =~/^\*+/) ;
    if ($line =~ /$delimiter/ ... $line =~/$delimiter/) {
    push (@lines, $line) ;
    }


}

print  $lines[0] ;
print  $lines[1] ;
print  $lines[2] ;

2 个答案:

答案 0 :(得分:2)

这似乎符合您的要求

我已将两行blahnothing2blahnothing3留在原位,因为我看不到删除它们的理由

\R正则表达式模式是通用换行符,并匹配来自任何平台的换行符序列,即CR,LF或CRLF

use strict;
use warnings 'all';

my $data = do {
    open my $fh, '<:raw', 'blah.txt' or die $!;
    local $/;
    <$fh>;
};

$data =~ s/^\s*\*.*\R/ /gm; # Remove lines starting with *
$data =~ s/\R/ /g;          # Change all line endings to spaces

# Split on pipe and remove blank elements
my @data = grep /\S/, split /\s*\|\s*/, $data; 

use Data::Dump;
dd \@data;

输出

[
  "blah1a blah1b blah1c",
  "blah2a blah2b blah2c",
  "blahnothing2",
  "blah3a blah3b blah3c",
  "blahnothing3 ",
]

答案 1 :(得分:1)

您似乎希望将|之间的行合并为一个字符串,该字符串将放置在数组中。

一种方法是将|设置为input record separator,因此每次在管道之间读取一个块

{  # localize the change to $/

    local $/ = "|";
    open(my $fh, '<:encoding(UTF-8)' , $filename) 
        or die "could not open file $filename $!";

    my @records;
    while (my $section = <$fh>)
    {
        next if $section =~ /^\s*\*/;  
        chomp $section;                # remove the record separator (| here)
        $section =~ s/\R/ /g;          # clean up newlines
        $section =~ s/^\s*//;          # clean up leading spaces
        push @records, $section if $section;
    }
    print "$_\n" for @records;
}

如果使用*启动(以及可选空格),我会跳过“部分”。可以有更多限制版本。 $section最终可能是一个emtpy字符串,因此我们有条件地在数组上push

输出,问题中的示例通过$filename

复制粘贴到输入文件中
blah1a blah1b blah1c 
blah2a blah2b blah2c 
blahnothing2 
blah3a blah3b blah3c 
blahnothing3 

问题中的方法很好,但您需要合并“部分”(管道之间)中的行并将每个这样的字符串放在数组上。因此,您需要一个标记来跟踪进入/离开某个部分的时间。