查找与块格式不匹配的行块
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
如果以上是您所期望的,那么您可以通过以下步骤完成。
- 以 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
$
现在删除不需要的模式。将上面的输出通过管道传输到另一个 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
$
再次使用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
谢谢
我有一个大文件,格式如下
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
如果以上是您所期望的,那么您可以通过以下步骤完成。
- 以 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
$
现在删除不需要的模式。将上面的输出通过管道传输到另一个 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
$
再次使用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
谢谢