Perl - 根据当前行中的匹配更改前一行中的所有匹配项

时间:2012-07-24 04:33:15

标签: perl multiline

我要解析的文件:

input Pattern;

input SDF;

input ABC

input Pattern;

output Pattern;

output XYZ;

在perl中,通常的操作是逐行扫描。 我想检查一下 当前行有output Pattern;,前一行(或前面所有行)都有input Pattern; 然后将所有上一行匹配更改为"input Pattern 2;",将当前行更改为"output Pattern2;"

这很复杂,我希望我已经解释得很好。 Perl是否有可能在读取之前扫描并更改以前的行?

由于

5 个答案:

答案 0 :(得分: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;

=&GT;

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;开始,然后随后增加。

答案 1 :(得分: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;

答案 2 :(得分:0)

您无法返回并更改Perl中的行。您可以做的是第一次在read模式下打开文件,找出哪个行具有模式(比如第5行),在将整个文件吞入数组之前将其关闭,然后在{ {1}}模式,将数组的内容修改到第5行,将该数组转储到该文件中,然后关闭它。这样的事情(假设每个文件最多只有一个输出模式):

write

答案 3 :(得分: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;

希望这有帮助!

答案 4 :(得分:0)

是否会有额外的&#34;输入模式1:线路出现&#34;输出Patttern1?&#34;

  1. 是否会有多种模式要搜索,或者只是#34;如果我们找到输出模式1然后执行替换?
  2. &#34;输出模式会多次出现,还是只出现一次?
  3. 是否会有额外的&#34;输入模式1:线路出现&#34;输出Patttern1?&#34;
  4. 我会在两次/多次通过中执行此任务:

    1. Pass1 - 读取文件,查找匹配的输出行,将行号存储在内存中。
    2. 传递2 - 读取文件,并根据匹配集中的行号,在相应的输入行上执行替换。
    3. 所以在半熟的,未经测试的伪代码中:

      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 
      

      您需要稍微调整一下以满足您的确切需求,但这应该会让您接近。