簡體   English   中英

多行匹配和解析

[英]Multiline matching and parsing

我有一些需要解析的數據在多行上。 我想在一行上包含數據的某些點,以便從中創建一個像結構的表。 數據各不相同。 有些分解成多行,有些則僅僅是2行。

樣本數據

方案1:

Start Anchor - First parse boundary
Name1 - Only one line of name
12345 - Number line needed
ending anchor - End parse boundary
data
data
data

方案2:

Start Anchor
name1 - Two lines of name.
name2
12345987
ending anchor
data
data
data

所需結果

方案1:

Name1  12345
data
data
data

方案2:

name1 name2  12345987
data
data
data

說明

因此,在此數據中,我需要在同一行上包含一個或多個名稱及其對應的編號。 我想將\\n替換為解析邊界之間的內容,同時仍然保留其余數據。

我目前的結果


方案1:

name1 12345987 - easy because only 1 line of name
data
data

方案2:

name1 name2 - tough part
12345987
data
data

my $text = read_file( 'list_2.txt' );
use File::Slurp;
$text =~ s/^Start Anchor\n(.*?)\n(.*?)ending anchor/$1 $2/gism;
print $text;
print;

在我眼中, $1變量應使用結尾錨來捕獲名稱。 $2變量應該捕獲該數字,因為它始終在結尾錨點上方一行。

是非貪婪的通配符打敗了您。 該模式^Start Anchor\\n(.*?)\\n(.*?)ending anchor會后的幾個字符地匹配Start Anchor\\n到下一個換行符,這是第一個名字線。 然后,下一個捕獲將匹配-盡可能少的字符,但此處沒有區別-匹配ending anchor ,這是第二個名字行和數字,以及它們之間的換行符,因為您有/s有效的修飾符。

解析內存中的整個文件很少是一項簡單的工作,通常更好的選擇是逐行讀取並保留狀態數據以記住您在結構中的位置。

在這種情況下,一個簡單的嵌套讀取循環就可以解決問題。 您沒有說在同一文件中是否可以出現多個塊,但是這種解決方案可以解決我認為您想要的那種情況。

use strict;
use warnings;

my @name;

while (<DATA>) {
  if (/^Start Anchor/) {
    while (<DATA>) {
      last if /^ending anchor/;
      chomp;
      push @name, $_;
    }
    print "@name\n";
    @name = ()
  }
  else {
    print;
  }
}

__DATA__
Start Anchor
Name1
12345
ending anchor
data
data
data

Start Anchor
name1
name2
12345987
ending anchor
data
data
data

產量

Name1 12345
data
data
data

name1 name2 12345987
data
data
data

您仍然可以逐行處理文件,只需記住您當前處於什么狀態或階段即可:

#!/usr/bin/perl
use warnings;
use strict;

my $state = 'search anchor';
my @names;
while (<DATA>) {
    if ('search anchor' eq $state and /Start Anchor/) {
        $state = 'collect names';

    } elsif ('collect names' eq $state) {

        chomp;
        push @names, $_;

        $state = 'expect ending anchor' if /^[0-9]+$/;

    } elsif ('expect ending anchor' eq $state) {

        die 'Ending anchor not found' unless /ending anchor/;
        $state = 'data';
        print "@names\n"

    } elsif ('data' eq $state) {

        if (/Start Anchor/) {
            $state = 'collect names';
            @names = ();

        } else {
            print;
        }
    }
}

__DATA__
Start Anchor
Name1
12345
ending anchor
data
data
data

Start Anchor
name1
name2
12345987
ending anchor
data
data
data

第二個名稱是可選的。 正則表達式使用eval修飾符對替換進行格式化。
它不是真正必要的,可以根據需要替換$1 $2 $3\\n

 # /(?xm)^Start\ Anchor\n\s*^(\w.*)\n(?:^(\w.*)\n)?\s*^(\d+).*\n\s*^ending\ anchor(?:\n|$)/

 (?xm-)
 ^ Start\ Anchor \n 
 \s* 
 ^ 
 ( \w .* )                          # (1), Name1 required
 \n 
 (?:
      ^ 
      ( \w .* )                     # (2), Name2 optional
      \n 
 )?
 \s* 
 ^ 
 ( \d+ )                            # (3), Numbers
 .* \n 
 \s* 
 ^ ending\ anchor
 (?: \n | $ )

Perl代碼:

use strict;
use warnings;

$/ = undef;

my $data = <DATA>;

$data =~ 
   s/
     ^Start\ Anchor\n\s*^(\w.*)\n(?:^(\w.*)\n)?\s*^(\d+).*\n\s*^ending\ anchor(?:\n|$)
    /
     "$1 ".(defined $2 ? "$2 " : "") . "$3\n"
    /exmg;

print $data, "\n";

__DATA__

Start Anchor
name1
12345
ending anchor
data
data
data


Start Anchor
name1
name2
12345987
ending anchor
data
data
data

輸出:

name1 12345
data
data
data


name1 name2 12345987
data
data
data

兩個技巧

  1. 逐行處理文件而不是拖拉

  2. 使用范圍運算符..進行跨越多行的邏輯

以下是對腳本的清理,該腳本可以按需工作:

use strict;
use warnings;
use autodie;

my $file = 'list_2.txt';

#open my $fh, '<', $file;
my $fh = \*DATA;

while (<$fh>) {
    if ( my $range = /^Start Anchor/ .. /^ending anchor/ ) {
        if ( $range =~ /E/ ) {
            print "\n";
        } elsif ( $range > 1 ) {
            chomp;
            print ' ' if $range > 2;
            print;
        }
    } else {
        print;
    }
}

__DATA__
Start Anchor
Name1
12345
ending anchor
data
data
data

Start Anchor
name1
name2
12345987
ending anchor
data
data
data

輸出:

Name1 12345
data
data
data

name1 name2 12345987
data
data
data

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM