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

Posted

技术标签:

【中文标题】查找与块格式不匹配的行块【英文标题】:Find block of lines that does not match block format 【发布时间】:2021-02-07 09:50:18 【问题描述】:

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

         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

没问题。但后来我被困住了。 可能最好使用sedawk 来解决它。 请指教。

谢谢!

【问题讨论】:

能否请您在您的问题中发布预期输出的示例,并让我们知道以更清楚,谢谢。 @RavinderSingh13 vim 搜索的标准输出。它只是将您带到您正在寻找的下一个事件。 【参考方案1】:

所以下面的 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

谢谢

【讨论】:

【参考方案2】:

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

$ 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

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

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

这可以使用

来完成
$ perl -ne ' if( /(?=^\s*0\s+0\s+0\s+0\s+?)(^.+?)\n/smgo )  print "\n$1"  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
$

    现在删除不需要的模式。将上述输出通过管道传递到另一个 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 ) print '

          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
    

    $

    再次,使用 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 ) print ' | awk ' BEGINOFS="\t" for(i=1;i

【讨论】:

以上是关于查找与块格式不匹配的行块的主要内容,如果未能解决你的问题,请参考以下文章

mysql 如何查找同一表中两行之间的差异并列出不匹配的记录? mysql在表中查找不匹配的行

用sql查找表之间不匹配的行

❤️Linux三剑客与管道符正则表达式的使用❤️

如何在不使用集合运算符的情况下在 oracle 中查找不匹配的行并加入 & 还查询特定行的不匹配列名

Linux-find

将不匹配的查找行插入表后如何继续该过程?