-1

我要解析的文件:

input Pattern;

input SDF;

input ABC

input Pattern;

output Pattern;

output XYZ;

在 perl 中,通常的操作是逐行扫描。我想检查当前行是否具有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;und 增量开始。

于 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

在 Perl 中,您不能返回并更改行。你可以做的是第一次以read模式打开文件,找出哪一行有模式(比如第5行),在将整个文件吞入一个数组之前关闭它,再次以write模式打开它,修改内容数组到第 5 行,将该数组转储到该文件中,然后关闭它。像这样(假设每个文件最多有一个输出模式):

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 回答
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. “输出模式会出现多次,还是只出现一次?
  3. 是否会有额外的“输入模式 1:出现“输出模式 1”的行?

我将在两次/多次传递中执行此任务:

  1. Pass1 - 读取文件,寻找匹配的输出行,将行号存储在内存中。
  2. Pass 2 - 读取文件,并根据匹配集中的行号,在适当的输入行上执行替换。

所以在半perlish,未经测试的伪代码中:

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 回答