我要解析的文件:
input Pattern;
input SDF;
input ABC
input Pattern;
output Pattern;
output XYZ;
在perl中,通常的操作是逐行扫描。
我想检查一下
当前行有output Pattern;
,前一行(或前面所有行)都有input Pattern;
然后将所有上一行匹配更改为"input Pattern 2;"
,将当前行更改为"output Pattern2;"
。
这很复杂,我希望我已经解释得很好。 Perl是否有可能在读取之前扫描并更改以前的行?
由于
答案 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;
我会在两次/多次通过中执行此任务:
所以在半熟的,未经测试的伪代码中:
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
您需要稍微调整一下以满足您的确切需求,但这应该会让您接近。