我正在处理perl脚本,需要一些帮助。要求是,我必须找到一个标签,一旦找到标签,我必须在标签后面的一行中替换该单词。例如,如果标签是ABC:
ABC:
string to be replaced
some other lines
ABC:
string to be replaced
some other lines
ABC:
string to be replaced
我想写一个匹配标签的脚本(ABC),一旦找到标签,就在标签后面的下一行替换一个单词。
这是我的尝试:
open(my $fh, "<", "file1.txt") or die "cannot open file:$!";
while (my $line = <$fh>))
{
next if ($line =~ /ABC/) {
$line =~ s/original_string/replaced_string/;
}
else {
$msg = "pattern not found \n ";
print "$msg";
}
}
这是正确的吗?任何帮助将不胜感激。
答案 0 :(得分:1)
你在循环中这样做:
next if ($line =~ /ABC/);
因此,您正在阅读该文件,如果该行中的任何位置包含ABC
,则跳过该行。但是,对于每隔一行,您都要进行替换。最后,您正在更换所有其他行上的字符串并将其打印出来,而不是打印出您的标签。
这就是你所说的:
所以:
遵循以下指示:
use strict;
use warnings; # Hope you're using strict and warnings
use autodie; # Program automatically dies on failed opens. No need to check
use feature qw(say); # Allows you to use say instead of print
open my $fh, "<", "file1.txt"; # Removed parentheses. It's the latest style
while (my $line = <$fh>) {
chomp $line; # Always do a chomp after a read.
if ( $line eq "ABC:" ) { # Use 'eq' to ensure an exact match for your label
say "$line"; # Print out the current line
$line = <$fh> # Read the next line
$line =~ s/old/new/; # Replace that word
}
say "$line"; # Print the line
}
close $fh; # Might as well do it right
请注意,当我使用say
时,我不必将\n
放在行尾。此外,通过阅读后我的chomp
,我可以轻松匹配标签而无需担心最后的\n
。
这完全按照你说应该完成的方式完成,但有几个问题。首先,当我们$line = <$fh>
时,我们无法保证我们真的在读一条线。如果文件在那里结束怎么办?
此外,在多个位置读取文件也是不好的做法。这使得维护程序变得更加困难。要解决此问题,我们将使用标志变量。这允许我们知道之前的行是否是标记:
use strict;
use warnings; # Hope you're using strict and warnings
use autodie; # Program automatically dies on failed opens. No need to check
use feature qw(say); # Allows you to use say instead of print
open my $fh, "<", "file1.txt"; # Removed parentheses. It's the latest style
my $tag_found = 0; # Flag isn't set
while (my $line = <$fh>) {
chomp $line; # Always do a chomp after a read.
if ( $line eq "ABC:" ) { # Use 'eq' to ensure an exact match for your label
$tag_found = 1 # We found the tag!
}
if ( $tag_found ) {
$line =~ s/old/new/; # Replace that word
$tag_found = 0; # Reset our flag variable
}
say "$line"; # Print the line
}
close $fh; # Might as well do it right
当然,我更愿意消除神秘的价值。例如,标记应该是变量或常量。与您要搜索的字符串和要替换的字符串相同。
你提到这是一个单词,所以你的正则表达式替换应该是这样的:
$line =~ s/\b$old_word\b/$new_word/;
\b
标记字边界。这样,如果你想用 dog 替换 cat 这个词,你就不会在一行上说:
The Jeopardy category is "Say what".
您不希望将category
更改为dogegory
。
答案 1 :(得分:1)
以下单行将满足您的需求:
perl -pe '++$x and next if /ABC:/; $x-- and s/old/new/ if $x' inFile > outFile
代码设置一个标志,如果找到标签,则获取下一行。如果设置了标志,则取消设置并执行替换。
希望这有帮助!
答案 2 :(得分:0)
您的问题是读取文件不是那样的。你是逐行进行的,所以当你的正则表达式测试为true时,你想要改变的行还没有。您可以尝试添加一个布尔变量来检查最后一行是否为标签。
#!/usr/bin/perl;
use strict;
use warnings;
my $found;
my $replacement = "Hello";
while(my $line = <>){
if($line =~ /ABC/){
$found = 1;
next;
}
if($found){
$line =~ s/^.*?$/$replacement/;
$found = 0;
print $line, "\n";
}
}
答案 3 :(得分:0)
或者你可以使用File :: Slurp并将整个文件读成一个字符串:
use File::Slurp;
$x = read_file( "file.txt" );
$x =~ s/^(ABC:\s*$ [\n\r]{1,2}^.*?)to\sbe/$1to was/mgx;
print $x;
使用/ m使^和$匹配嵌入的开始/结束行
x是允许$后面的空格 - 可能有更好的方式
产率:
ABC:
string to was replaced
some other lines
ABC:
string to was replaced
some other lines
ABC:
string to was replaced
答案 4 :(得分:0)
另外,依靠perl的in-place editing:
use File::Slurp qw(read_file write_file);
use strict;
use warnings;
my $file = 'fakefile1.txt';
# Initialize Fake data
write_file($file, <DATA>);
# Enclosed is the actual code that you're looking for.
# Everything else is just for testing:
{
local @ARGV = $file;
local $^I = '.bac';
while (<>) {
print;
if (/ABC/ && !eof) {
$_ = <>;
s/.*/replaced string/;
print;
}
}
unlink "$file$^I";
}
# Compare new file.
print read_file($file);
1;
__DATA__
ABC:
string to be replaced
some other lines
ABC:
string to be replaced
some other lines
ABC:
string to be replaced
ABC:
<强>输出强>
ABC:
replaced string
some other lines
ABC:
replaced string
some other lines
ABC:
replaced string
ABC: