-1

解析したいファイル:

input Pattern;

input SDF;

input ABC

input Pattern;

output Pattern;

output XYZ;

perl では、通常の操作は 1 行ずつスキャンします。output Pattern;現在の行と前の行 (または前のすべての行) がinput Pattern; に一致し"input Pattern 2;"、現在の行が に一致するかどうかを確認したい"output Pattern2;"

複雑です。適切に説明していただければ幸いです。Perl で、読み取った後に前の行をスキャンして変更することは可能ですか?

ありがとう

4

5 に答える 5

2

これがあなたのデータである場合:

my $sfile =
'input Pattern;
input SDF;
input ABC
input Pattern;
output Pattern;
output XYZ;' ;

次に、次のスニペットがファイル全体を読み取り、それに応じてテキストを変更します。

open my $fh, '<', \$sfile or die $!;
local $/ = undef;                # set file input mode to 'slurp'
my $content = <$fh>;
close $fh;

$content =~ s{ (                   # open capture group
                input \s+ (Pattern); # find occurence of input pattern
                .+?                  # skip some text
                output \s+ \2        # find same for output
               )                   # close capture group
             }
             {                     # replace by evaluated expression
              do{                    # within a do block
                 local $_=$1;        # get whole match to $_
                 s/($2)/$1 2/g;      # substitute Pattern by Pattern 2
                 $_                  # return substituted text
                }                    # close do block
             }esgx;

次に、ファイルを閉じて文字列を確認します。

print $content;

=>

input Pattern 2;
input SDF;
input ABC
input Pattern 2;
output Pattern 2;
output XYZ;

一致が成功するたびにインクリメントされるカウンター$nを含めることもできます(コードアサーションによって(?{ ... })

our $n = 1;

$content =~ s{ (                   # open capture group
                input \s+ (Pattern); # find occurence of input pattern
                .+?                  # skip some text
                output \s+ \2        # find same for output
                )                  # close capture group
                (?{ $n++ })        # ! update match count 
             }
             {                     # replace by evaluated expression
              do{                    # within a do block
                 local $_=$1;        # get whole match to $_
                 s/($2)/$1 $n/g;     # substitute Pattern by Pattern and count
                 $_                  # return substituted text
                }                  # close do block
             }esgx;

置換は、input Pattern 2;その後undincrementで開始されます。

于 2012-07-24T09:45:49.743 に答える
0
#!/usr/bin/env perl

$in1 = 'input Pattern';
$in2 = 'input Pattern2';
$out1 = 'output Pattern';
$out2 = 'output Pattern2';

undef $/;
$_ = <DATA>;
if (/^$in1\b.*?^$out1\b/gms) {
    s/(^$in1\b)(?=.*?^$out1\b)/$in2/gms;
    s/^$out1\b/$out2/gms;
}
print;

__DATA__
input Pattern;
input SDF;
input ABC;
input Pattern;
output Pattern;
output XYZ;
于 2012-07-24T05:17:30.410 に答える
0

これで必要なことができると思いますが、実際にファイルを変更するため、最初に「スクラッチ」ファイル(オリジナルのコピー)で試してください:

use Modern::Perl;

open my $fh_in, '<', 'parseThis.txt' or die $!;
my @fileLines = <$fh_in>;
close $fh_in;

for ( my $i = 1 ; $i < scalar @fileLines ; $i++ ) {
    next
      if $fileLines[$i] !~ /output Pattern;/
          and $fileLines[ $i - 1 ] !~ /input Pattern;/;
    $fileLines[$i] =~ s/output Pattern;/output Pattern2;/g;
    $fileLines[$_] =~ s/input Pattern;/input Pattern 2;/g for 0 .. $i - 1;
}

open my $fh_out, '>', 'parseThis.txt' or die $!;
print $fh_out @fileLines;
close $fh_out;

結果:

input Pattern 2;
input SDF;
input ABC;
input Pattern 2;
output Pattern2;
output XYZ;

お役に立てれば!

于 2012-07-24T06:35:36.637 に答える
0

追加の「入力パターン 1: 「出力パターン 1」の発生に続く行はありますか?

  1. 検索するパターンが複数あるのでしょうか、それとも単に「出力パターン 1 が見つかったら置換を実行しますか?
  2. 「出力パターンは複数回発生しますか、それとも 1 回だけ発生しますか?
  3. 追加の「入力パターン 1: 「出力パターン 1」の発生に続く行はありますか?

このタスクを 2 回または複数回のパスで実行します。

  1. Pass1 - ファイルを読み取り、一致する出力行を探し、行番号をメモリに保存します。
  2. パス 2 - ファイルを読み取り、一致するセットの行番号に基づいて、適切な入力行で置換を実行します。

したがって、半パーリッシュでテストされていない疑似コードでは、次のようになります。

my @matches = ();
open $fh, $inputfile, '<';
while (<$fh>) {
   if (/Pattern1/) {
     push @matches, $.;
   }
}
close $fh;

open $fh, $inputfile, '<';
while (<$fh>) {
  if ($. <= $matches[-1]) {
    s/Input Pattern1/Input Pattern2/;
    print ;
  }
  else {
    pop @matches);
    last unless @matches;
  }
}
close $fh;

これを次のように実行します。

      $ replace_pattern.pl input_file > output_file 

正確なニーズに合わせて少し調整する必要がありますが、それで近づくはずです.

于 2012-07-24T14:56:10.923 に答える
0

Perl では、戻って行を変更することはできません。あなたができることは、モードで初めてファイルを開き、readどの行にパターンがあるかを見つけ(5行目など)、ファイル全体を配列に丸呑みにする前に閉じ、writeモードで再度開き、内容を変更することです5 行目までの配列をそのファイルにダンプし、それを閉じます。このようなもの(各ファイルに最大1つの出力パターンがあると仮定):

my @arr;
my @files = ();
while (<>) {
    if ($. == 0) {
        $curindex = undef;
        @lines    = ();
        push @files, $ARGV;
    }
    push @lines, $_;
    if (/output pattern/) { $curindex = $. }
    if (eof) {
        push @arr, [\@lines, $curindex];
        close $ARGV;
    }
}

for $file (@files) {
    open file, "> $file";
    @currentfiledetails  = @{ $arr[$currentfilenumber++] };
    @currentcontents     = @{ $currentfiledetails[0] };
    $currentoutputmarker = $currentfiledetails[1];
    if ($currentoutputmarker) {
        for (0 .. $currentoutputmarker - 2) {
            $currentcontents[$_] =~ s/input pattern/input pattern2/g;
        }
        $currentcontents[$currentoutputmarker - 1] =~
            s/output pattern/output pattern2/g;
    }
    print file for @currentcontents;
    close file;
}
于 2012-07-24T05:51:24.950 に答える