查找与块格式不匹配的行块

Find block of lines that does not match block format

我有一个大文件,格式如下

         0           0           0           0
      5522     -365290     -441287      -78074
    -39490      -30774        7921       82126
   1391898     1139913      792801     2672554
         0           0           0           0
      4906     -366163     -441744      -77614
    -39125      -31009        7332       81061
   1412373     1142806      793817     2837307
         0           0           0           0

我需要找到那些不符合这种格式的行块。 例如,四行以零为界的数字块 行:

         0           0           0           0                                                                                                                    
     15965     -463075     -549574      -89243
    -64152      -45009       17963      103367
   -189486     -165820     -128253     -236536
   1243199     1029337      734157     2290154
         0           0           0           0

格式不符。 我只需要找到这样的块。 我会根据上下文手动修复它们。

同时我在 vim 中有以下查询:

/\s0           0\n.*\n.*\n.*\n/^\(\(\s0\)\@!.\)*$

这实际上行不通。 我很确定这部分:

\s0           0\n.*\n.*\n.*\n

没问题。但后来我被困住了。 大概用sed或者awk来解决比较好。 请指教

谢谢!

我假设您的输入文件如下所示。

$ cat block_zeros.txt
         0           0           0           0
      5522     -365290     -441287      -78074
    -39490      -30774        7921       82126
   1391898     1139913      792801     2672554
         0           0           0           0
      4906     -366163     -441744      -77614
    -39125      -31009        7332       81061
   1412373     1142806      793817     2837307
         0           0           0           0
     15965     -463075     -549574      -89243
    -64152      -45009       17963      103367
   -189486     -165820     -128253     -236536
   1243199     1029337      734157     2290154
         0           0           0           0
      5000     -300000     -400000      -70000
    -30000      -30000        7000       80000
         0           0           0           0
$

并且您需要删除该模式

         0           0           0           0
     15965     -463075     -549574      -89243
    -64152      -45009       17963      103367
   -189486     -165820     -128253     -236536
   1243199     1029337      734157     2290154
         0           0           0           0

预期的输出如下。

0        0        0        0
5522     -365290  -441287  -78074
-39490   -30774   7921     82126
1391898  1139913  792801   2672554
0        0        0        0
4906     -366163  -441744  -77614
-39125   -31009   7332     81061
1412373  1142806  793817   2837307
0        0        0        0
5000     -300000  -400000  -70000
-30000   -30000   7000     80000
0        0        0        0

如果以上是您所期望的,那么您可以通过以下步骤完成。

  1. 以 0 0 0 0 作为记录的开头,在您看到另一个 0 0 0 0 模式之前加入后续行。

这可以使用

来完成
$ perl -ne ' if( /(?=^\s*0\s+0\s+0\s+0\s+?)(^.+?)\n/smgo ) { print "\n" } else { chomp($_); print "$_" } '  block_zeros.txt

         0           0           0           0      5522     -365290     -441287      -78074    -39490      -30774        7921       82126   1391898     1139913      792801     2672554
         0           0           0           0      4906     -366163     -441744      -77614    -39125      -31009        7332       81061   1412373     1142806      793817     2837307
         0           0           0           0     15965     -463075     -549574      -89243    -64152      -45009       17963      103367   -189486     -165820     -128253     -236536   1243199     1029337      734157     2290154
         0           0           0           0      5000     -300000     -400000      -70000    -30000      -30000        7000       80000
         0           0           0           0
$
  1. 现在删除不需要的模式。将上面的输出通过管道传输到另一个 perl 命令,如下所示

    $ perl -ne ' if( /(?=^\s0\s+0\s+0\s+0\s+?) (^.+?)\n/smgo ) { 打印 "\n$1" } else { chomp($);打印 "$" } ' block_zeros.txt | perl -ne ' if(! /(^\s0\s+0\s+0\s+0\s+15965)/omg ) { 打印 } '

          0           0           0           0      5522     -365290     -441287      -78074    -39490      -30774        7921       82126   1391898     1139913      792801     2672554
          0           0           0           0      4906     -366163     -441744      -77614    -39125      -31009        7332       81061   1412373     1142806      793817     2837307
          0           0           0           0      5000     -300000     -400000      -70000    -30000      -30000        7000       80000
          0           0           0           0
    

    $

  2. 再次使用awk展开

    $ perl -ne ' if( /(?=^\s0\s+0\s+0\s+0\s+?) (^.+?)\n/smgo ) { 打印 "\n$1" } else { chomp($);打印 "$" } ' block_zeros.txt | perl -ne ' if(! /(^\s0\s+0\s+0\s+0\s+15965)/omg ) { 打印 } ' | awk ' BEGIN{OFS="\t" } { for(i=1;i<=NF;i=i+4) { 打印 $i,$(i+1),$(i+2),$( i+3) } } ' |列-t 0 0 0 0 5522 -365290 -441287 -78074 -39490 -30774 7921 82126 1391898 1139913 792801 2672554 0 0 0 0 4906 -366163 -441744 -77614 -39125 -31009 7332 81061 1412373 1142806 793817 2837307 0 0 0 0 5000 -300000 -400000 -70000 -30000 -30000 7000 80000 0 0 0 0 $

所以下面的 vim 搜索查询实现了我想要实现的目标

/\(\s\+0\)\{4}\n.*\n.*\n.*\n^\(\(\s+0\)\{4}\)\@!

它找到包含在两行之间的所有行块,每行四行 0 并且行数大于 3。

\(\s\+0\)\{4} 寻找一行 4 个零,每个 0 前面至少有一个空格

\n.*\n.*\n.* 后跟 3 行任意内容

\n^\(\(\s+0\)\{4}\)\@! 后面没有一行 4 个零

所以它会找到这样的块

         0           0           0           0                                                                                                                    
     15965     -463075     -549574      -89243
    -64152      -45009       17963      103367
   -189486     -165820     -128253     -236536
   1243199     1029337      734157     2290154
         0           0           0           0

然后这样屏蔽

     0           0           0           0                                                                                                                    
 15965     -463075     -549574      -89243
-64152      -45009       17963      103367
     0           0           0           0

谢谢