使用awk提取和打印模式的第一次出现

3
我正在尝试使用 awk 提取并打印出第一个出现的 NM_ 以及之后以 p. 开头的NP_ 部分。每个 "|" 的位置将被替换为 :。输入文件是 tab-delimeted,但输出不需要是这种格式。下面的代码可执行,但会打印文件中的所有行,而非只有指定的模式。我的实际数据中可能有多个 NMNP,但只有每个的第一次出现会被提取和打印。我对 RSTARTRLENGHTH 的概念仍有些不清楚,以输入的第一行为例:

NM 变量将是 NM_020469.2

NP 变量将是 :p.Gly268Arg

我也加入了注释。谢谢 :)

输入

Input Variant   HGVS description(s) Errors and warnings
rs41302905  NC_000009.11:g.136131316C>T|NM_020469.2:c.802G>A|NP_065202.2:p.Gly268Arg
rs8176745   NC_000009.11:g.136131347G>A|NM_020469.2:c.771C>T|NP_065202.2:p.Pro257=

期望输出

rs41302905 NM_020469.2:c.802G>A:p.Gly268Arg
rs8176745 NM_020469.2:c.771C>T:p.Pro257=

awk

awk -F'[\t|]' 'NR>1{ # define FS as tab and `|` to split each, and skip header line
              r=$1; nm=np="";  # create variable r with $1 and 2 variables (one for nm and the other for np, setting them to null)
              for(i=2;i<=NF;i++) { # start a loop from line2 and itterate
                  if ($i~/^NM_/) nm=$i;  # extract first NM_ in line and read into i
                  else if ($i~/^NP_/) np=substr($i,index($i,":")); # extract NP_ and print portion after : (including :)
                  if (nm && np) { print r,nm np; break }  # print desired output
              }
          }' input

1
还在谈论“模式”吗?叹气.... 如果我的实际数据中可能有多个NM或NP,则在示例数据中至少显示2个,否则您会引发错误问题的解决方案。 - Ed Morton
5个回答

1
Awk解决方案:
awk -F'[\t|]' 'NR>1{
                  r=$1; nm=np="";
                  for(i=2;i<=NF;i++) {
                      if ($i~/^NM_/) nm=$i;
                      else if ($i~/^NP_/) np=substr($i,index($i,":"));
                      if (nm && np) { print r,nm np; break } 
                  }
              }' input

  • 'NR>1 - 从第二条记录开始处理

  • r=$1; nm=np="" - 初始化所需变量

  • for(i=2;i<=NF;i++) - 遍历字段(从第二个字段开始)

  • if ($i~/^NM_/) nm=$i - 将NM_...项捕获到变量nm

  • else if ($i~/^NP_/) np=substr($i,index($i,":")) - 将NP_...项捕获到变量np中(从:开始直到结尾)

  • if (nm && np) { print r,nm np; break } - 如果两个项都被捕获-打印它们并跳出循环以避免进一步处理


输出:

rs41302905 NM_020469.2:c.802G>A:p.Gly268Arg
rs8176745 NM_020469.2:c.771C>T:p.Pro257=

非常完美,非常感谢 :). 我想我明白了,但在我的帖子中编辑的评论是否正确/接近?再次感谢。 - justaguy
@Chris,不客气。你还有我的额外赠品gawk解决方案https://dev59.com/86Xja4cB1Zd3GeqPUKBL#46525760(如果你喜欢简短的一行代码)。 - RomanPerekhrest

1

你能否尝试一下以下方法,并让我知道是否有帮助。

awk '{
match($0,/NM_[^|]*/);
nm=substr($0,RSTART,RLENGTH);
match($0,/NP_([^|]|[^$])*/);
np=substr($0,RSTART,RLENGTH);
split(np, a,":");
  if(nm && np){
    print $1,nm ":" a[2]
}
}
'   Input_file

输出将如下所示。
rs41302905 NM_020469.2:c.802G>A:p.Gly268Arg
rs8176745 NM_020469.2:c.771C>T:p.Pro257=

注:由于您的示例输入文件中没有制表符,因此如果您的输入文件是以制表符分隔的,则可以在 awk 后面添加 "\t"。如果您希望输出也是以制表符分隔的,请在 Input_file 之前添加 OFS="\t"。


1

短的GNU awk解决方案(使用match函数):

awk 'match($0,/(NM_[^|]+).*NP_[^:]+([^[:space:]|]+)/,a){ print $1,a[1] a[2] }' input

输出:

rs41302905 NM_020469.2:c.802G>A:p.Gly268Arg
rs8176745 NM_020469.2:c.771C>T:p.Pro257=

1
根据您发布的示例输入,这是您需要生成所需输出的全部内容。
$ awk -F'[\t|]+' 'NR>1{sub(/[^:]+/,"",$4); print $1, $3 $4}' file
rs41302905 NM_020469.2:c.802G>A:p.Gly268Arg
rs8176745 NM_020469.2:c.771C>T:p.Pro257=

如果这不是你所需要的全部内容,那么请提供更真实代表性的输入/输出。


1

另一个关于awk的备选方案。

awk 'NR>1{sub(/\|/," ")sub(/\|NP_065202.2/,"");print $1,$3,$4}' file

rs41302905 NM_020469.2:c.802G>A:p.Gly268Arg
rs8176745 NM_020469.2:c.771C>T:p.Pro257=

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接