匹配字符并从底部行提取数据



我有一个用制表符分隔的大文件,其中一部分类似于:

25      M   X   A   A   X   S
25_a    M   K   A   A   R   S
25_b    M   A   A   A   V   S
31      M   A   A   A   V   S
31_a    M   A   A   A   V   S
31_b    M   A   A   A   V   S

我试图一次玩三行,第一行包含一个引用序列(实际序列(,而接下来的两行反映了它的变体。我试着做两件事:

第一件事是,从第一行(参考线(25((开始,我试图识别(匹配(一个字符(X(,并试图只保留底部两行(25_a,25_b(中的相应字符,以获得如下所示的内容,

25      M   X   A   A   X   S
25_a        K           R   
25_b        A           V   

其次,如果参考(31(行中没有(X(,则删除相应的两行(31_a,31_b(,得到如下内容:

31      M   A   A   A   V   S

最终输出应该像一样

25      M   X   A   A   X   S
25_a        K           R   
25_b        A           V   
31      M   A   A   A   V   S

我知道我们可以使用sed命令删除特定字符后的内容,但我很难获得所需的输出。如有任何帮助,将不胜感激

这可能对你有用(GNU sed(:

sed -E 'N;N;/^.._./!{/^S+s.*X/!{P;d};s/^(S+s*)(.*nS+s*)(.*nS+s*)/1n2n3n/;:a;/nn/{s/n+/n/g;s/.$//;b};s/n([Xt])(.*n.*)n(.)(.*n.*)n(.)/1n23n45n/;ta;s/n(.)(.*n.*)n(.)(.*n.*)n(.)/1n2n4n/;ta}' file

将接下来的两行追加到当前行。

如果参考行不包含X,则打印第一行并删除其余两行。

否则:插入三条换行符,每条换行符都跟在模式空间中三行的键后面。

使用循环,测试第一个插入换行符后面的字符是X还是制表符,如果是,则将换行符移到它上面,并对其他两行执行相同操作。

如果插入的换行符后面的字符不是上述任一字符,请将其移到参考行的上面,然后将其从其他两行中删除。

重复此步骤,直到处理完第一行的全部内容。

在行处理结束时,插入的换行符将被删除并打印结果。

给定这个输入(我在这里使用了空格使其更漂亮,但它应该是制表符(

25      a   X   X   q   X   c
25_a    b   g   l   r   w   d
25_b    c   h   m   s   y   e
31      d   i   0   0   z   f
41      d   i   X   X   z   f
41_a    e   j   o   u   a   g
41_b    f   k   p   v   b   h
41_c    f   k   p   v   b   h
47      d   i   0   0   z   f
47_a    e   j   o   u   a   g
47_b    f   k   p   v   b   h

和这个期望的输出(空格应该是制表符(

25      a   X   X   q   X   c
25_a    b           r       d
25_b    c           s       e
31      d   i   0   0   z   f
41      d   i   X   X   z   f
41_a    e   j           a   g
41_b    f   k           b   h
41_c    f   k           b   h
47      d   i   0   0   z   f

以下脚本完成了这项工作:

#!/usr/bin/env -S sed -Ef
/^[0-9]+t/!d
/^[0-9]+t.*X/{
:next
N
/.*n[0-9]+_[^n]*$/!bprint
:mark
s/^([^n]*)t([^tx0][^n]*n)/1x02/
s/^(.*)n(.*)t([^tx0])([^n]*)$/1n2x034/
tmark
:clean
/^([^x0]*)x0[^X]/s/^([^x0]*)x0(.*)n([^x0]*)x0(.*)$/1t2n3t4/
/^([^x0]*)x0X/s/^([^x0]*)x0X(.*)n([^x0]*)x0.(.*)$/1tX2n3t4/
tclean
bnext
:print
h
s/(.*)n.*/1/
p
x
s/.*n(.*)/1/
/X/bnext
}

这个脚本比必要的更通用,因为它处理任意数量的行或列。我还用一个包含大量Xes(第240到260列(的小卡盘测试了您的输入,它很有效。

另一方面,它非常缓慢。我可以通过考虑线总是以3为一组来简化它;这肯定会降低脚本的复杂性。

但更笼统地做这件事很有趣。

最新更新