2017-01-31 8 views
0

私はフリップフロップを使って過去に異なるSTART & ENDのテキストを抽出することができました。 今度は、フリップフロップのSTART & ENDが同じであるため、ソースファイルに異なるデリミタがないため、テキストを抽出するのに苦労しています。 yyyy年のラインの存在が&のときに、$_を別の行がyyyyを開始するまで配列にプッシュし続けると、フリップフロップが真に始まります。 フリップフロップの問題は、次のSTARTでfalseになることです。perlフリップフロップを使用してSAMEデリミタ間のテキストを抽出

while (<SOURCEFILE>) { 
    print if (/^2017/ ... /^2017/) 
} 

上記のソースデータを使用すると、ファイルの2番目の複数行部分が見つからなくなるため、一致する必要があります。多線ファイルを解析する最良の方法だと思ったフリップフロップは、この場合にはうまくいかないでしょうか?私がしたいのは、日付が&で始まる最初の行とのマッチングを開始し、日付で始まる次の行の前の行までマッチングを続けます。

2017 message 1 
Text 
Text 

Text 

2017 message 2 
more text 
more text 

more text 

2017 message 3 
yet more text 
yet more text 

yet more text 

しかし、私は取得しています::

サンプルデータがある

2017 message 1 
Text 
Text 

Text 

2017 message 2 
2017 message 3 
yet more text 
yet more text 

yet more text 

...行方不明のメッセージ2つの内容..私はスペースまたは異なるENDの区切り文字に依存することはできません

私のソースデータで。 私は、各メッセージを印刷する(実際にはpush @myarray, $_ &)と試しましたが、フリップフロップがfalseに設定されているため、メッセージ2の下に行がありません。フリップフロップでこれを処理する方法は何ですか?または何か他のものを使用する必要がありますか? 事前に助けて助言できる人に感謝します。

答えて

1

私はflipflopでそれを行う方法がわかりません。私は1年前にそれを試しました。しかし、同じことを私はいくつかのロジックでやった。ここで

my $line_concat; 
my $f = 0; 
while (<DATA>) { 
    if(/^2017/ && !$f) { 
     $f = 1; 
    } 

    if (/^2017/) { 
     print "$line_concat\n" if $line_concat ne ""; 
     $line_concat = ""; 
    } 

    $line_concat .= $_ if $f; 
} 

print $line_concat if $line_concat ne ""; 
+0

@simbabque友だちに感謝します。投稿が編集されました。 – mkHun

+0

もう1つ...それは動作しますが、あなたは決して '$ f'をリセットしません。何故なの? 2つ目の 'if'ブロックにリセットと' redo'を入れて、それぞれのペアを実際にペアにすることができますが、それを行う際に利点はありません。 – simbabque

2

は、移動するための方法である:

use Modern::Perl; 
use Data::Dumper; 
my $part = -1; 
my $parts; 
while(<DATA>) { 
    chomp; 
    if (/^2017/ .. 1==0) { 
     $part++ if /^2017/; 
     push @{$parts->[$part]}, $_; 
    } 
} 
say Dumper$parts; 

__DATA__ 
2017 message 1 
Text 
Text 

Text 

2017 message 2 
more text 
more text 

more text 

2017 message 3 
yet more text 
yet more text 

yet more text 

出力:

$VAR1 = [ 
      [ 
      '2017 message 1', 
      'Text', 
      'Text', 
      '', 
      'Text', 
      '' 
      ], 
      [ 
      '2017 message 2', 
      'more text', 
      'more text', 
      '', 
      'more text', 
      '' 
      ], 
      [ 
      '2017 message 3', 
      'yet more text', 
      'yet more text', 
      '', 
      'yet more text' 
      ] 
     ]; 
+0

うーん、よく目に付きます。その 'if'行は実際には重複しているのですか? – Sobrique

+1

@Sobrique、それは '/^2017 /'にマッチする最初の行の前に行をスキップするために使われます。 – ikegami

1

あなたが見つけたとしてマッチした区切り文字を持つフリップフロップが、あまりうまく機能しません。 。

代わりに$/と設定したことがありますか?

例えば:

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

local $/ = "2017 message"; 
my $count; 

while (<DATA>) { 

    print "\nStart of block:", ++$count, "\n"; 

    print; 

    print "\nEnd of block:", $count, "\n"; 
} 

__DATA__ 
2017 message 1 
Text 
Text 

Text 

2017 message 2 
more text 
more text 

more text 

2017 message 3 
yet more text 
yet more text 

yet more text 

それが区切り文字でファイルを分割するので、それは、完璧ではないですが - 最初のものの前に「ビット」はあります意味(あなたが4つのチャンクを取得します)。あなたは、現在のチャンクから$/を削除「ムシャムシャ食べる」の賢明な使用、とそれをrespliceことができます。

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

local $/ = "2017 message"; 
my $count; 

while (<DATA>) { 
    #remove '2017 message' 
    chomp; 
    #check for empty (first) block 
    next unless /\S/; 
    print "\nStart of block:", ++$count, "\n"; 
    #re add '2017 message' 
    print $/; 
    print; 

    print "\nEnd of block:", $count, "\n"; 
} 

また、どのように配列の配列について、あなたは「ターゲット・キー」あなたがメッセージを打つたびに更新すること?

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

use Data::Dumper; 

my %messages; 
my $message_id; 
while (<DATA>) { 
    chomp; 
    if (m/2017 message (\d+)/) { $message_id = $1 }; 
    push @{ $messages{$message_id} }, $_; 
} 

print Dumper \%messages; 

注 - それはゼロから連続して起動しないメッセージシーケンシングのために少しより堅牢なので、私は、ハッシュではなく、配列を使用しています。 (このアプローチを使用する配列は空の '0番目の要素'を持つ)。

注 - 空白行の場合は、空の''要素もあります。あなたはしかし、それらをフィルタリングすることができます。

1

/^20\d\d[ ]/またはファイルの終わりに一致するものが見つかるまで、行を累積するバッファが必要です。

my $in = 0; 
my @buf; 
while (<>) { 
    if ($in && /^20\d\d[ ]/) { 
     process(@buf); 
     @buf =(); 
     $in = 0; 
    } 

    push @buf, $_ if $in ||= /^2017[ ]/; 
} 

process(@buf) if $in; 

我々はprocessをインライン化することができるように、レコードは1箇所のみで処理されているので、それを作るためのコードを並べ替えることができます。

my $in = 0; 
my @buf; 
while (1) { 
    $_ = <>; 

    if ($in && (!defined($_) || /^20\d\d[ ]/)) { 
     process(@buf); 
     @buf =(); 
     $in = 0; 
    } 

    last if !defined($_); 

    push @buf, $_ if $in ||= /^2017[ ]/; 
} 
+0

上記のコメントは決して正確ではなく、答えの変更によって廃止されました。 – ikegami

関連する問題