keep fasta records which have 2 matches of OX values

烂漫一生 提交于 2020-05-16 22:05:02

问题


I have a file that looks as follows :

>sp|rin-1 ghsfdhjkuesl OX=10116 GN=Cdh1 PE=1 SV=1|sp|P10287|ghsfdjdeosd gdhkhs OX=10090 GN=Cdh3 PE=1 SV=2
WRDTANWLEINPETGVISTRAEMDREDSEHVKNSTYTALIIATDDGSPIATGTGTLLLVLSDVNDNAPIPEPRNMQFCQRNPKPHVITILDPDLPP
>sp|erin-1 ghsfdshkd OX=10116 GN=Cdh1 PE=1 SV=1|sp|P22223|CADH3_HUMAN Cadherin-3 OX=9606 GN=CDH3 PE=1 SV=2
ESYPTYTLVVQAADLQGEGLSTTAKAVITVKDINDNAPIFNPSTYLQCAASEPCRAVFREAEVTLEAGGAEQEPGQALGKVFMGCPGQEPALFSTD
>sp|n-1 ghsfd OX=10116 GN=Cdh1 PE=1 SV=1|tr|F1LMI3|ghsfdhsj dghe OX=10116 GN=Cdh3 PE=4 SV=3
MGARCRSFSALLLLLQVSSWLCQQPESESDSCRPGFSSEVYTFLVPERHLERGHILGRVKFEGCTGRPRTAFFSEDSRFKVSTDGVITVKRHLKLH

I want to keep only those records where there are two matches of OX values,hence,the desired output should like the following :

>sp|n-1 ghsfd OX=10116 GN=Cdh1 PE=1 SV=1|tr|F1LMI3|OX=10116 GN=Cdh3 PE=4 SV=3
MGARCRSFSALLLLLQVSSWLCQQPESESDSCRPGFSSEVYTFLVPERHLERGHILGRVKFEGCTGRPRTAFFSEDSRFKVSTDGVITVKRHLKLH

The code I have tried is following :

awk -v p="OX=" 'FNR==1{x=0}{x+=gsub(p,p);if(x>2){print $line}}' test.fasta

回答1:


I came up with this awk script, which seems to work.

awk '
    printnext == 1 {                          #Prints the line after the line w 2 matches
        print;
        printnext=0;
    }
    match($0, /OX=[0-9]*/) {                  #Looks for OX=numbers
        id=substr($0,RSTART,RLENGTH);         #Saves it to id
        c=0;
        for (i=1;i<=NF;i++){                  #Looks for two occurrences of id in line
            if ($i==id){
                c=c+1;
                if (c==2) {print;printnext=1}
            }
        }
    }
' test.fasta



回答2:


How about this one, without using loop. Could you please try following. Will add detailed explanation in few mins.

awk '
match($0,/OX=[0-9]+/){
  val=substr($0,RSTART,RLENGTH)
  if(gsub(val,"&")==2){
    print
    found=1
  }
  val=""
  next
}
found{
  found=""
  print
}
' Input_file

OR a small editing in above solution where remove val="" part as per @Quasimodo comment:

awk '
match($0,/OX=[0-9]+/){
  val=substr($0,RSTART,RLENGTH)
  if(gsub(val,"&")==2){
    print
    found=1
  }
  next
}
found{
  found=""
  print
}
' Input_file

Explanation: Adding a detailed explanation for above code.

awk '                               ##Starting awk program from here.
match($0,/OX=[0-9]+/){              ##Using match function to match OX= digits in current line.
  val=substr($0,RSTART,RLENGTH)     ##Creating variable val whose value is sub-string of value of current line starts from RSTART till value of RLENGTH.
  if(gsub(val,"&")==2){             ##Checking condition if value of Global substitutions is equal to 2 then do following.
    print                           ##Printing the current line.
    found=1                         ##Setting variable found value as 1 here.
  }
  val=""                            ##Nullifying variable val here.
  next                              ##next will skip all further statements from here.
}
found{                              ##Checking condition if variable found is NOT NULL then do following.
  found=""                          ##Nullifying variable found here.
  print                             ##Printing current line here.
}
'  Input_file                       ##Mentioning Input_file name here.


EDIT: NOTE, this code is trying to cover an edge case if anyone's samples are exact same as shown by OP then above codes should be Good enough.

Trying to cover an edge case here mentioned by @kvantour in comments, changed regex a bit where it checks like OX should be preceded and followed by a space.

awk '
match($0,/\s+OX=[0-9]+\s+/){
  val=substr($0,RSTART,RLENGTH)
  if(gsub(val,"&")==2){
    print
    found=1
  }
  val=""
  next
}
found{
  found=""
  print
}
'  Input_file



回答3:


With GNU awk, you can use patsplit and split by desired content vs by some delimiter.

Given:

$ cat test.fasta
>sp|rin-1 ghsfdhjkuesl OX=10116 GN=Cdh1 PE=1 SV=1|sp|P10287|ghsfdjdeosd gdhkhs OX=10090 GN=Cdh3 PE=1 SV=2
WRDTANWLEINPETGVISTRAEMDREDSEHVKNSTYTALIIATDDGSPIATGTGTLLLVLSDVNDNAPIPEPRNMQFCQRNPKPHVITILDPDLPP
>sp|erin-1 ghsfdshkd OX=10116 GN=Cdh1 PE=1 SV=1|sp|P22223|CADH3_HUMAN Cadherin-3 OX=9606 GN=CDH3 PE=1 SV=2
ESYPTYTLVVQAADLQGEGLSTTAKAVITVKDINDNAPIFNPSTYLQCAASEPCRAVFREAEVTLEAGGAEQEPGQALGKVFMGCPGQEPALFSTD
>sp|n-1 ghsfd OX=10116 GN=Cdh1 PE=1 SV=1|tr|F1LMI3|ghsfdhsj dghe OX=10116 GN=Cdh3 PE=4 SV=3
MGARCRSFSALLLLLQVSSWLCQQPESESDSCRPGFSSEVYTFLVPERHLERGHILGRVKFEGCTGRPRTAFFSEDSRFKVSTDGVITVKRHLKLH

You can split and capture by value pairs, in this case by OX=:

$ awk -v RS=$'>' '{
             cnt=patsplit($0, arr, "OX=[0-9]+") 
             if (cnt==2 && arr[1]==arr[2]) 
                printf ">%s", $0
            }' test.fasta   
>sp|n-1 ghsfd OX=10116 GN=Cdh1 PE=1 SV=1|tr|F1LMI3|ghsfdhsj dghe OX=10116 GN=Cdh3 PE=4 SV=3
MGARCRSFSALLLLLQVSSWLCQQPESESDSCRPGFSSEVYTFLVPERHLERGHILGRVKFEGCTGRPRTAFFSEDSRFKVSTDGVITVKRHLKLH



回答4:


awk -F'[O][X][=]' '{a=$0; gsub(/ .*/,"",$2) ; gsub(/ .*/,"",$3) ;  if ($2==$3) print a }'

Demo

:>cat regular_expressions_are_greedy.txt
>sp|rin-1 ghsfdhjkuesl OX=10116 GN=Cdh1 PE=1 SV=1|sp|P10287|ghsfdjdeosd gdhkhs OX=10090 GN=Cdh3 PE=1 SV=2WRDTANWLEINPETGVISTRAEMDREDSEHVKNSTYTALIIATDDGSPIATGTGTLLLVLSDVNDNAPIPEPRNMQFCQRNPKPHVITILDPDLPP
>sp|erin-1 ghsfdshkd OX=10116 GN=Cdh1 PE=1 SV=1|sp|P22223|CADH3_HUMAN Cadherin-3 OX=9606 GN=CDH3 PE=1 SV=2ESYPTYTLVVQAADLQGEGLSTTAKAVITVKDINDNAPIFNPSTYLQCAASEPCRAVFREAEVTLEAGGAEQEPGQALGKVFMGCPGQEPALFSTD
>sp|n-1 ghsfd OX=10116 GN=Cdh1 PE=1 SV=1|tr|F1LMI3|ghsfdhsj dghe OX=10116 GN=Cdh3 PE=4 SV=3MGARCRSFSALLLLLQVSSWLCQQPESESDSCRPGFSSEVYTFLVPERHLERGHILGRVKFEGCTGRPRTAFFSEDSRFKVSTDGVITVKRHLKLH
:>awk -F'[O][X][=]' '{a=$0; gsub(/ .*/,"",$2) ; gsub(/ .*/,"",$3) ;  if ($2==$3) print a }' regular_expressions_are_greedy.txt
>sp|n-1 ghsfd OX=10116 GN=Cdh1 PE=1 SV=1|tr|F1LMI3|ghsfdhsj dghe OX=10116 GN=Cdh3 PE=4 SV=3MGARCRSFSALLLLLQVSSWLCQQPESESDSCRPGFSSEVYTFLVPERHLERGHILGRVKFEGCTGRPRTAFFSEDSRFKVSTDGVITVKRHLKLH
:>

Explanation:

awk -F'[O][X][=]'  <---  Setting field separator as  "OX="
'{
a=$0; <-- Saving input record in variable a. ($0 = Means whole records)
gsub(/ .*/,"",$2) ; <-- Removing all character after space from column 1 
gsub(/ .*/,"",$3) ;  <-- Removing all character after space from column 2
if ($2==$3) <-- Checking if 2 values are equal. 
print a 
}'



回答5:


A very quick way would be to do something like this:

awk '/^>/{p=0;delete a
          for(i=1;i<=NF;++i) a[$i]++
          for(i in a) if (i ~ /^OX=/ && a[i]>1) p=1
         }
     p' file

This will match cases such as:

> foobar OX=1 OX=2 OX=3 OX=1
ABCDEF

A bit more optimized if you care only about the string OX=, you can do:

awk '/^>/{p=0;delete a
          for(i=1;i<=NF;++i) if($i ~ /^OX=/) a[$i]++
          for(i in a) if (a[i]>1) p=1
         }
     p' file


来源:https://stackoverflow.com/questions/60497313/keep-fasta-records-which-have-2-matches-of-ox-values

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!