Regex 如何在sed中匹配模式前后注释()6行
我想在匹配模式前后评论6行。 我提到了这个问题 我尝试对此解决方案使用保留缓冲区,但不起作用 我在一个文件中多次出现以下序列:Regex 如何在sed中匹配模式前后注释()6行,regex,perl,vim,sed,Regex,Perl,Vim,Sed,我想在匹配模式前后评论6行。 我提到了这个问题 我尝试对此解决方案使用保留缓冲区,但不起作用 我在一个文件中多次出现以下序列: aaaa bbbb cccc dddd eeee ffff gggg hhhh iiii jjjj kkkk llll mmmm nnnn oooo 如果我搜索了hhh,那么输出文件应该如下所示: aaaa #bbbb #cccc #dddd #eeee #ffff
aaaa
bbbb
cccc
dddd
eeee
ffff
gggg
hhhh
iiii
jjjj
kkkk
llll
mmmm
nnnn
oooo
如果我搜索了hhh,那么输出文件应该如下所示:
aaaa
#bbbb
#cccc
#dddd
#eeee
#ffff
#gggg
#hhhh
#iiii
#jjjj
#kkkk
#llll
#mmmm
#nnnn
oooo
请帮助我用sed或任何其他脚本完成此操作 **这里有一个Perl解决方案** 我将把整个内容存储在一个数组中,遍历数组,如果模式匹配,则标记迭代器变量。然后从迭代器变量中删除并添加6,然后我们开始,如果给出了标记的变量,您可以在该行前面的hashtag处进行concate 更清楚地说:
use File::Slurp;
my $find_counter = 0;
my $line_counter = 0;
my @lines = read_file( 'filename' ) ;
foreach my $line (@lines) { # foreach or for loop
if ($line =~ /$pattern/) {
$file_counter = $line_counter;
last;
}
$line_counter++;
}
# loop again through @lines and when the line is between
# $file_counter + - 6 , concat the hashtag in front of the line
**下面是一个Perl解决方案** 我将把整个内容存储在一个数组中,遍历数组,如果模式匹配,则标记迭代器变量。然后从迭代器变量中删除并添加6,然后我们开始,如果给出了标记的变量,您可以在该行前面的hashtag处进行concate 更清楚地说:
use File::Slurp;
my $find_counter = 0;
my $line_counter = 0;
my @lines = read_file( 'filename' ) ;
foreach my $line (@lines) { # foreach or for loop
if ($line =~ /$pattern/) {
$file_counter = $line_counter;
last;
}
$line_counter++;
}
# loop again through @lines and when the line is between
# $file_counter + - 6 , concat the hashtag in front of the line
问题被标记为Vim,所以…我的爱人:帮助:全球和:帮助:正常救援
:g/hhhh/-6,+6norm I#
:替换变量:
细分:
:global命令用于对与给定模式匹配的每一行执行Ex命令
:g/hhh/d将删除包含hhh的每一行
Ex命令通常接受可选范围。范围可以使用绝对行号、5、15和/或相对行号、-3、+41
:g/hhh/-6,+6d将删除包含hhh的每一行上面6行和下面6行之间的所有内容
:normal命令允许我们从命令行执行普通命令,它接受一个范围,就像其他Ex命令一样。I是在行首插入a的最简单方法,因此我们可以执行以下操作:从命令行执行普通I,这将我们带到第一个解决方案:
:g/hhhh/-6,+6norm I#
:g/hhhh/-6,+6s/^/#
作为一个Ex命令,:substitute也接受一个范围,因此我们也可以使用它在范围中每行的开头插入一个,这就引出了第二个解决方案:
:g/hhhh/-6,+6norm I#
:g/hhhh/-6,+6s/^/#
问题被标记为Vim,所以…我的爱人:帮助:全球和:帮助:正常救援
:g/hhhh/-6,+6norm I#
:替换变量:
细分:
:global命令用于对与给定模式匹配的每一行执行Ex命令
:g/hhh/d将删除包含hhh的每一行
Ex命令通常接受可选范围。范围可以使用绝对行号、5、15和/或相对行号、-3、+41
:g/hhh/-6,+6d将删除包含hhh的每一行上面6行和下面6行之间的所有内容
:normal命令允许我们从命令行执行普通命令,它接受一个范围,就像其他Ex命令一样。I是在行首插入a的最简单方法,因此我们可以执行以下操作:从命令行执行普通I,这将我们带到第一个解决方案:
:g/hhhh/-6,+6norm I#
:g/hhhh/-6,+6s/^/#
作为一个Ex命令,:substitute也接受一个范围,因此我们也可以使用它在范围中每行的开头插入一个,这就引出了第二个解决方案:
:g/hhhh/-6,+6norm I#
:g/hhhh/-6,+6s/^/#
要在Perl中实现这一点,您需要将整个文件读入一个数组,然后找到匹配行的索引并编辑周围的行,这可以在一个范围内完成 必须从数组切片中删除未定义的值,否则,如果匹配项接近文件的开头或结尾,即相距不到6行,则将创建新条目
perl -we '@a = <>; # read whole file
for (0 .. $#a) { # loop over indexes
if ($a[$_] =~ /hhhh/) { # find match
s/^/#/ for grep defined, @a[$_-6 .. $_+6] # edit
}
}; print @a" hhh.txt
要在Perl中实现这一点,您需要将整个文件读入一个数组,然后找到匹配行的索引并编辑周围的行,这可以在一个范围内完成 必须从数组切片中删除未定义的值,否则,如果匹配项接近文件的开头或结尾,即相距不到6行,则将创建新条目
perl -we '@a = <>; # read whole file
for (0 .. $#a) { # loop over indexes
if ($a[$_] =~ /hhhh/) { # find match
s/^/#/ for grep defined, @a[$_-6 .. $_+6] # edit
}
}; print @a" hhh.txt
另一种方法是一次读取一行,这对于大型文件可能更好,它避免了将整个文件读入内存 数组@prev_line保存匹配前要打印的行数。找到匹配项后,使用前缀打印记住的行,并将$num_line_to_print设置为匹配后要打印的行数。如果行不匹配,则查看是否要打印前一个匹配的行。如果两者都不匹配,则将线推到阵列上,以防将来匹配。如果数组现在有太多的行,则它们与匹配的行不接近,因此只需打印它们即可。最后,在while循环之后,只需打印出任何保存行
use strict;
use warnings;
my $num_lines_wanted = 6;
my @prev_lines;
my $num_line_to_print = 0;
while ( <> ) {
if ( m/hhhh/ ) {
while ( scalar(@prev_lines) > 0 ) {
print "#", shift @prev_lines;
}
print "#", $_;
$num_line_to_print = $num_lines_wanted;
}
elsif ( $num_line_to_print > 0 ) {
print "#", $_;
$num_line_to_print--;
}
else {
push @prev_lines, $_;
if ( scalar(@prev_lines) > $num_lines_wanted ) {
print shift @prev_lines;
}
}
}
while ( scalar(@prev_lines) > 0 ) {
print shift @prev_lines;
}
最初的问题不清楚如何处理两条hhhh行在彼此的六行之内的输入。这里的代码在每次匹配时重新开始编号,它只打印一次输入行,即使一行在两个hhhh匹配的范围内,也只添加一行。另一种方法是一次读取一行,这对于大型文件可能更好,它可以避免读取整个文件 进入记忆 数组@prev_line保存匹配前要打印的行数。找到匹配项后,使用前缀打印记住的行,并将$num_line_to_print设置为匹配后要打印的行数。如果行不匹配,则查看是否要打印前一个匹配的行。如果两者都不匹配,则将线推到阵列上,以防将来匹配。如果数组现在有太多的行,则它们与匹配的行不接近,因此只需打印它们即可。最后,在while循环之后,只需打印出任何保存行
use strict;
use warnings;
my $num_lines_wanted = 6;
my @prev_lines;
my $num_line_to_print = 0;
while ( <> ) {
if ( m/hhhh/ ) {
while ( scalar(@prev_lines) > 0 ) {
print "#", shift @prev_lines;
}
print "#", $_;
$num_line_to_print = $num_lines_wanted;
}
elsif ( $num_line_to_print > 0 ) {
print "#", $_;
$num_line_to_print--;
}
else {
push @prev_lines, $_;
if ( scalar(@prev_lines) > $num_lines_wanted ) {
print shift @prev_lines;
}
}
}
while ( scalar(@prev_lines) > 0 ) {
print shift @prev_lines;
}
最初的问题不清楚如何处理两条hhhh行在彼此的六行之内的输入。此处的代码在每次匹配时重新开始编号,它只打印一次输入行,即使一行在两个hhhh匹配范围内,也只添加一行。这可能适用于您所使用的:
sed -r ':a;s/\n/&/6;tb;$!{N;ba};:b;/SEARCH_STRING/!{P;D};s/\n/&/12;tc;$!{N;bb};:c;s/^/#/gm' file
这可能适用于GNU sed:
sed -r ':a;s/\n/&/6;tb;$!{N;ba};:b;/SEARCH_STRING/!{P;D};s/\n/&/12;tc;$!{N;bb};:c;s/^/#/gm' file
对于那些熟悉sed的人,我建议使用grep将上下文传输到sed,以创建一些简单的sed命令: grep-A6-B6-n hhhh文件| sed-e的/[^0-9].$/'-e的/$/s | ^ | | sed-f文件 下面的示例使用-A1和-B1来缩短此输出的长度 使用grep-A1-B1-n hhh文件获取匹配行后面的-A1行和前面的-B1行,该文件输出: 7-gggg 8:hhhh 9-iiii 。。。我们希望通过管道将这些命令传递给sed,因此我们使用-f-它相当于-f/dev/stdin,并指示sed从stdin读取命令 grep-A1-B1-n hhh abcd.txt | sed-e's/[^0-9].$/'-e's/$/s | ^ | | sed-f-abcd.txt
对于那些熟悉sed的人,我建议使用grep将上下文传输到sed,以创建一些简单的sed命令: grep-A6-B6-n hhhh文件| sed-e的/[^0-9].$/'-e的/$/s | ^ | | sed-f文件 下面的示例使用-A1和-B1来缩短此输出的长度 使用grep-A1-B1-n hhh文件获取匹配行后面的-A1行和前面的-B1行,该文件输出: 7-gggg 8:hhhh 9-iiii 。。。我们希望通过管道将这些命令传递给sed,因此我们使用-f-它相当于-f/dev/stdin,并指示sed从stdin读取命令 grep-A1-B1-n hhh abcd.txt | sed-e's/[^0-9].$/'-e's/$/s | ^ | | sed-f-abcd.txt
好的,给我几分钟。哦,哇。我喜欢维姆。我希望我能投你两次票。谢谢。这也可以作为“一次性”完成,而不是像这样:global:/hhh/-6、+6 s/^/norm I也有效。模式设置光标位置,因为;,请参阅:帮助:;,那么有效范围就是-6,+6。@ChrisJohnsen,非常有价值的评论,谢谢。我也是这样做的,但是OP说他的样本块在一个文件中出现了多次,所以我采用了更全局的方法。好的,给我几分钟。哦,哇。我喜欢维姆。我希望我能投你两次票。谢谢。这也可以作为“一次性”完成,而不是像这样:global:/hhh/-6、+6 s/^/norm I也有效。模式设置光标位置,因为;,请参阅:帮助:;,那么有效范围就是-6,+6。@ChrisJohnsen,非常有价值的评论,谢谢。我也是这样做的,但是OP说他的示例块在一个文件中出现了多次,所以我采用了更全局的方法。@joshy没有问题。我只是想指出问题的一个未指明的方面,以及我的回答是如何处理的。@joshy没问题。我只是想指出这个问题的一个未明确的方面,以及我的回答是如何处理的。我扩展了一行并添加了一些解释。我扩展了一行并添加了一些解释