搜索并替换文件中的多行

Search and replace multiple lines from a file

我正在尝试删除 a.txt 文件的一部分并替换为 b.txt 文件的内容,同时还使用 Perl 程序修改 a.txt 中的其他行。

文件a.txt

line1
line2 
replace from below line
replace from this line
bla bla...
bla bla...
to this line
line3
line4

文件b.txt

replacement1
replacement2
replacementn 

下面是我的代码,但无法正常工作。

#!/apps/perl/5.8.3/bin/perl -w
   open (INPUT, "a.txt")              or die $!;
   open (REPLACE, "b.txt")            or die $!;
   open (OUTPUT, ">c.txt")          or die $!;

my $replace_text;
{
    local $/;
    $replace_text = <REPLACE>;
}
close(REPLACE);

while (<INPUT>) {
   s/line1/modified_line1/;
   s/line2/modified_line2/;
   
   if($_ =~ /replace from below line/){
       while(<INPUT>){
             {
                local undef $/;
                s/replace from this line.*to this line/$replace_text/smg;
             }
       s/line3/modified_line3/;
       s/line4/modified_line4/;
       print OUTPUT;
   }
}
}
close(INPUT);
close(OUTPUT);

预期输出文件c.txt

modified_line1
modified_line2
replacement1
replacement2
replacementn
modified_line3
modified_line4

有人可以帮助我了解哪里出错了吗?

我认为您不需要嵌套 while 循环来读取您的输入文件。

一种方法是使用变量来控制打印到输出文件的时间:

use warnings;
use strict;

open (INPUT, "a.txt")   or die $!;
open (REPLACE, "b.txt") or die $!;
open (OUTPUT, ">c.txt") or die $!;

my $replace_text;
{
    local $/;
    $replace_text = <REPLACE>;
}
close(REPLACE);

my $print = 1;
while (<INPUT>) {
    s/line(\d)/modified_line/;
    $print = 0 if /replace from below line/;
    if (/to this line/) {
        $print = 1;
        $_ = $replace_text;
    }
    print OUTPUT if $print;
}
close(INPUT);
close(OUTPUT);

输出:

modified_line1
modified_line2 
replacement1
replacement2
replacementn
modified_line3
modified_line4

我还使用 \d 将你的 4 个 line 替换合并为 1 个。

尽管我很喜欢perl,但这里真的没有必要:

sed -e 's/line1/modified_line1/' \
    -e 's/line2/modified_line2/' \
    -e 's/line3/modified_line3/' \
    -e 's/line4/modified_line4/' \
    -e '/replace from below/rb.txt' \
    -e '/replace from below/,/to this line/d' a.txt
modified_line1
modified_line2
replacement1
replacement2
replacementn
modified_line3
modified_line4

如果你确实想使用 perl,我会这样做:

#!/usr/bin/env perl
use strict;
use warnings;
open my $ah, '<', "a.txt" or die "a.txt: $!\n";

while(<$ah>) {
        s/line1/modified_line1/;
        s/line2/modified_line2/;
        s/line3/modified_line3/;
        s/line4/modified_line4/;
        if( /replace from below/ ){
                system "cat b.txt" and exit 1;
        }
        next if( /replace from below/ .. /to this line/);
        print;
}

问题描述没有指定a.txt文件可以有多大。发布的代码使用带有修饰符 /smg 的正则表达式,这表明 OP 尝试处理多行文本。

假设输入文件足够小,可以在内存中读取和处理。

为了代码可管理性,替代品放入 __DATA__ 块中,该块读取 %substitute 哈希。

基于 keys %substitute 构建正则表达式 $re 以在替换模式中使用。

多行替换基于原始OP的代码(不适用于逐行读取输入数据)。

定义了两个子例程以将文件内容读入变量并将变量数据存储到文件中 -- 只是为了使代码更易于阅读和理解。

use strict;
use warnings;
use feature 'say';

my($fname_in,$fname_repl,$fname_out) = qw/a.txt b.txt c.txt/;

my %substitute = split(/[,\s]/, do{ local $/; <DATA>} );
my $re = '\b(' . join('|',keys %substitute) . ')\b';

my $data = read_file($fname_in);
my $replace_with = read_file($fname_repl);

$data =~ s/$re/$substitute{}/g;
$data =~ s/replace from below line.*?to this line/$replace_with/gsm;

save_file($fname_out,$data);
say $data;

exit 0;

sub read_file {
    my $fname = shift;
    my $data;
    
    open my $fh, '<', $fname
        or die "Couldn't open $fname";
    $data = do { local $/; <$fh> };
    close $fh;
    
    return $data;
}

sub save_file {
    my $fname = shift;
    my $data  = shift;
    
    open my $fh, '>', $fname
        or die "Couldn't open $fname";
    say $fh $data;
    close $fh;
}

__DATA__
line1,modified_line1
line2,modified_line2
line3,modified_line3
line4,modified_line4

输出

modified_line1
modified_line2
replacement1
replacement2
replacementn
modified_line3
modified_line4