Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Regex 如何在sed中匹配模式前后注释()6行_Regex_Perl_Vim_Sed - Fatal编程技术网

Regex 如何在sed中匹配模式前后注释()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

我想在匹配模式前后评论6行。 我提到了这个问题

我尝试对此解决方案使用保留缓冲区,但不起作用

我在一个文件中多次出现以下序列:

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没问题。我只是想指出这个问题的一个未明确的方面,以及我的回答是如何处理的。我扩展了一行并添加了一些解释。我扩展了一行并添加了一些解释