我正在尝试打开文件,在文件中搜索特定字符串以开始搜索,然后在文件中对字符串执行替换。例如,我的文件如下:
测试旧
Hello World
旧
数据
Begin_search_here
新数据
旧数据
新数据
我想打开文件,从“Begin_search_here”开始搜索,然后用“New”替换单词“Old”的下一个实例。我的代码如下所示,我正确地找到了字符串,但由于某种原因,我没有写在正确的位置。
open(FILE, "+<$filename") || die "problem opening file";
my search = 0;
while(my $line = <FILE>)
{
if($line =~ m/Begin_search_here/)
{
$search = 1;
}
if($search == 1 && $line =~m/Old/)
{
$line = s/Old/New/;
print FILE $line
}
close FILE;
答案 0 :(得分:4)
这里你去:
local $^I = '.bak';
local @ARGV = ($filename);
local $_;
my $replaced = 0;
while (<>) {
if (!$replaced && /Begin_search_here/ .. $replaced) {
$replaced = s/Old/New/;
}
print;
}
说明:
设置$^I
变量可以进行就地编辑,就像使用-i
标志运行perl一样。原始文件将以与原始文件相同的名称保存,但扩展名为“.bak”;如果您不想进行备份,请将".bak"
替换为""
。
@ARGV
设置为要进行就地编辑的文件列表;这里只是您在变量$filename
中命名的单个文件。
$_
已本地化,以防止在子代码中出现此代码段时覆盖此常用变量。
触发器操作符..
用于确定要执行替换的文件的哪个部分。在第一次遇到匹配模式Begin_search_here
的行时,它将为false,并且然后将保持为真,直到第一次发生替换(如变量$replaced
中所记录的那样),它将关闭。
答案 1 :(得分:1)
您滥用随机访问文件模式。当您更新$line
并说print FILE $line
时,文件句柄的“光标”已经位于 next 行的开头。因此,原始行不会更改,下一行会被覆盖,而不是覆盖原始行。
现场编辑(请参阅perlrun
)看起来非常适合此问题。
否则,您需要阅读tell
函数以在读取行之前保存文件位置,并在重写行之前将seek
返回到该位置。哦,你写的数据必须与你覆盖的数据大小完全相同,否则你将完全满足你的文件 - 见this question。
答案 2 :(得分:1)
通过以读取模式(open( my $fh, '<', $file ) or die ...;
)打开输入文件,并将修改后的文本写入临时输出文件,然后在输入文件的顶部复制临时文件时,最好能得到满意的服务完成你的处理。
答案 3 :(得分:1)
我做了很多像这样的编辑,我提出了一个通用的(但是精简的)策略:
use strict;
use warnings;
use English qw<$INPLACE_EDIT>;
use Params::Util qw<_CODE>;
local $INPLACE_EDIT = '.bak';
local @ARGV = '/path/to/file';
my @line_actions
= ( qr/^Begin_search_here/
, qr/^Old Data/ => sub { s/^Old/New/ }
);
my $match = shift @line_actions;
while ( <> ) {
if ( $match and /$match/ ) {
if ( _CODE( $line_actions[0] )) {
shift( @line_actions )->( $_ );
}
$match = shift @line_actions;
}
print;
}
答案 4 :(得分:0)
这很有效。正如您所指定的那样,它只会替换一次。
#! /usr/bin/perl -pi.bak
if (not $match_state) {
if (/Begin_search_here/) {
$match_state = "accepting";
}
}
elsif ($match_state eq "accepting") {
if (s/Old/New/) {
$match_state = "done";
}
}
答案 5 :(得分:0)
在编辑文件时要非常小心。如果您要替换的数据长度不同,则会破坏该文件。此外,如果你的程序在中间失败,你最终会得到一个被破坏的文件。
您最好的选择是读取每一行,处理该行,并将每行写入新文件。这甚至允许您运行程序,检查输出,如果有错误,请修复它并重新运行程序。然后,一旦一切正常,请添加步骤以将新文件移动到旧名称。
我从版本3.x开始一直在使用Perl,我想不出有一次我修改了文件。
use strict;
use warnings;
open (INPUT, "$oldfile") or die qq(Can't open file "$oldFile" for reading);
open (OUTPUT, "$oldfile.$$") or die qq(Can't open file "$oldfile.$$" for writing);
my $startFlag = 0;
while (my $line = <INPUT>) {
if ($line ~= /Begin_search_here/) {
$startFlag = 1;
}
if ($startFlag) {
$line =~ s/New/Old/;
}
print OUTPUT "$line";
}
#
# Only implement these two steps once you've tested your program
#
unlink $oldfile;
rename $oldfile.$$", $oldfile;