1 |
#!/usr/bin/perl |
2 |
use strict; |
3 |
use Getopt::Std; |
4 |
use FindBin;use lib $FindBin::Bin; |
5 |
my $usage = q{ |
6 |
Script for parsing RefSeq mRNAs in GenBank File Format. |
7 |
Usage: |
8 |
gbrna2fa.pl [-P][-R] genbank_format_stream |
9 |
|
10 |
Use -P option in order to exclude the PREDICTED mRNAs and gene models. |
11 |
Use -R option to only write the REVIEWED and VALIDATED entries |
12 |
}; |
13 |
|
14 |
umask 0002; |
15 |
getopts('PR') || die($usage."\n"); |
16 |
my %refseqtype=( |
17 |
'INFERRED'=> 'inf', # usually not yet supported by experimental evidence |
18 |
'MODEL' => 'mod', #usually predicted by GNOMON |
19 |
'PREDICTED' => 'p', # only CDS is predicted in most cases, the mRNA is experimentally confirmed |
20 |
# (it becomes 'px' then) |
21 |
'PROVISIONAL' => 'pv', #usually based on experimental evidence, but not "reviewed" by NCBI |
22 |
'VALIDATED' => 'v', # preliminary reviewed, but did not go through "final review" |
23 |
'REVIEWED' => 'r' |
24 |
); |
25 |
|
26 |
#my $outfile=$Getopt::Std::opt_g; |
27 |
#my $fastaout=$Getopt::Std::opt_F; |
28 |
my %typeflt=('mod'=>1,'p'=>1,'inf'=>1,'px'=>1,'pv'=>1, 'v'=>1, 'r'=>1, 'gb'=>1); |
29 |
|
30 |
my $nopred=$Getopt::Std::opt_P; |
31 |
my $onlyrev=$Getopt::Std::opt_R; |
32 |
|
33 |
if ($nopred || $onlyrev) { |
34 |
@typeflt{'mod', 'inf', 'p'}=(0,0,0); |
35 |
} |
36 |
|
37 |
if ($onlyrev) { |
38 |
@typeflt{'pv','px'}=(0,0); |
39 |
} |
40 |
|
41 |
my %gnames; |
42 |
#if ($fastaout) { |
43 |
# open(FASTAOUT, '>'.$fastaout)|| die ("Error creating file $fastaout\n"); |
44 |
# } |
45 |
#if ($outfile) { |
46 |
# open(GFFOUT, '>'.$outfile) || die ("Error creating file $outfile\n"); |
47 |
# select(GFFOUT); |
48 |
# } |
49 |
my ($bseq, $fseq, $descr, $bGI, $bACC, $blen, $org, $comment, $cds, $cdsprod, |
50 |
$geneid, $freading, $seqreading); |
51 |
my $skipLocus=0; |
52 |
while (<>) { |
53 |
chomp; |
54 |
NEXTLINE: |
55 |
if (m/^LOCUS/) { |
56 |
($bseq, $blen)=(m/^LOCUS\s+(\S+)\s+(\d+)/); |
57 |
die("Error parsing LOCUS tag info: $_\n") unless $blen; |
58 |
if ($blen<20 || $blen>300000 || m/\s+DNA\s+linear\s+/) { |
59 |
while(<>) { |
60 |
chomp; |
61 |
goto NEXTLINE if m/^LOCUS/; |
62 |
} |
63 |
} |
64 |
} |
65 |
elsif (m/^DEFINITION\s+(.+)/) { |
66 |
$descr=$1; |
67 |
while (<>) { |
68 |
chomp; |
69 |
if (m/^[A-Z]+\s+/) { |
70 |
$descr=~tr/\t \n\r/ /s; |
71 |
goto NEXTLINE; |
72 |
} |
73 |
$descr.=' '.$_; |
74 |
} |
75 |
$descr=~tr/\t \n\r/ /s; |
76 |
next; |
77 |
} |
78 |
elsif (m/^ACCESSION\s+(\S+)/) { |
79 |
$bACC=$1; |
80 |
next; |
81 |
} |
82 |
elsif (m/^VERSION/) { |
83 |
($bACC, $bGI)=(m/([\w\.]+)\s+GI:(\d+)/); |
84 |
die("Error parsing GI# from VERSION tag ($_)") unless $bGI>1; |
85 |
next; |
86 |
} |
87 |
elsif (m/^SOURCE\s+(.+)/) { |
88 |
$org=$1; |
89 |
next; |
90 |
} |
91 |
elsif (m/^COMMENT\s+(.+)/) { |
92 |
$comment=$1; |
93 |
while (<>) { |
94 |
chomp; |
95 |
if (m/^\s*[A-Z]+\s+/) { |
96 |
goto NEXTLINE; |
97 |
} |
98 |
$comment.=' '.$_; |
99 |
} |
100 |
next; |
101 |
} |
102 |
elsif (m/^FEATURES\s+/) { |
103 |
$freading=1; |
104 |
next; |
105 |
} |
106 |
# elsif (m/^BASE COUNT/) { |
107 |
# $freading=0; |
108 |
# next; |
109 |
# } |
110 |
elsif (m/^CONTIG\s+/) { |
111 |
$freading=0; |
112 |
$seqreading=0; |
113 |
} |
114 |
elsif (m/^ORIGIN\s+/) { |
115 |
$freading=0; |
116 |
$seqreading=1; |
117 |
next; |
118 |
} |
119 |
elsif (m/^\/\/$/) { |
120 |
$freading=0; |
121 |
$seqreading=0; |
122 |
my $defline=$bACC; |
123 |
my ($ctype)=($comment=~m/^([A-Z]+)\s+/); |
124 |
my $rtype; |
125 |
if ($ctype && ($rtype=$refseqtype{$ctype})) { |
126 |
$rtype.='x' if $comment=~m/is supported by experimental/; |
127 |
#$defline=$rtype.'|'.$bACC; |
128 |
} |
129 |
else { |
130 |
$rtype='gb'; |
131 |
} |
132 |
$defline=$rtype.'|'.$bACC; |
133 |
# non refseq entries will not have rtype set |
134 |
if (length($fseq)>20 && $typeflt{$rtype}==1) { |
135 |
$descr=~s/\,\s+mRNA\.$//; |
136 |
$descr=~s/\.$//; |
137 |
$descr=~s/\s*\(\Q$geneid\E\)// if $geneid; |
138 |
$descr=~s/^$org\s+//; |
139 |
if ($cdsprod) { |
140 |
$cdsprod=~tr/\t \n\r/ /s; |
141 |
if (!$descr || $descr=~m/hypothetical/i) { |
142 |
$descr=$cdsprod; |
143 |
} |
144 |
else { |
145 |
#print STDERR "{$descr}\n{$cdsprod}\n"; |
146 |
$descr.=' product:'.$cdsprod |
147 |
unless (index(lc($descr), lc($cdsprod))>=0 || $cdsprod=~m/hypothetical protein/i); |
148 |
} |
149 |
} |
150 |
$defline.=' gid:'.$geneid if $geneid; |
151 |
$defline.=' '.$cds if $cds; |
152 |
$defline.=' '.$descr; |
153 |
$defline.=' {'.$org.'}'; |
154 |
$defline =~ tr/ \t/ /s; |
155 |
print &fastafmt(\$fseq, $defline); |
156 |
} |
157 |
$fseq=''; |
158 |
$descr=''; |
159 |
$bseq=''; |
160 |
$geneid=''; |
161 |
$comment=''; |
162 |
$cds=''; |
163 |
$cdsprod=''; |
164 |
$comment=''; |
165 |
next; |
166 |
} |
167 |
|
168 |
#-- remaining lines parsing: |
169 |
|
170 |
if ($freading) { |
171 |
my ($featname, $frange)=(m/^\s+([\w\'\-]+)\s+(.+)/); |
172 |
die("Error parsing $bACC feature at: $_\n") unless $featname && $frange; |
173 |
if ($frange=~m/\(/ && $frange!~m/\)$/) { #wrapped composite intervals line |
174 |
do { |
175 |
$_=<>; |
176 |
last unless $_; |
177 |
chomp; |
178 |
$frange.=$_; |
179 |
} until (m/\)$/); |
180 |
} #unwrapped the composite intervals (multi-exons) |
181 |
if ($featname eq 'CDS') { |
182 |
$cds.='|' if $cds; |
183 |
$frange=~s/\.\./-/g; |
184 |
$frange=~tr/ //d; |
185 |
# for join() ranges or partial < > |
186 |
$frange=~ s/^[^\d]*(\d+).+?(\d+)\)?$/$1-$2/; |
187 |
$cds.='CDS:'.$frange; |
188 |
} |
189 |
|
190 |
my @attrs; |
191 |
my $endattr; |
192 |
#print STDERR "..reading attributes for $featname ($frange)\n"; |
193 |
while (<>) { #read all attributes for this feature |
194 |
unless (m/^\s+\/\w+/) { |
195 |
$endattr=1; |
196 |
last; |
197 |
} |
198 |
chomp; |
199 |
if (m/^\s+\/([\w\-]+)=(.+)/) { |
200 |
my ($a, $av)=($1, $2); |
201 |
my ($fattr, $fattr_dta)=&parseAttr($featname, $a,$av); #this will read the next line(s) if necessary |
202 |
if ($fattr eq 'gene' && !$geneid) { |
203 |
$geneid=$fattr_dta; |
204 |
#$gname =~ tr/"//d; #" |
205 |
next; |
206 |
} |
207 |
if ($featname eq 'CDS' && $fattr eq 'product') { |
208 |
$cdsprod=$fattr_dta; |
209 |
# if (!$descr || $descr=~m/hypothetical/i) { |
210 |
# $descr=$fattr_dta; |
211 |
# } |
212 |
# else { $cdsprod=' product:'.$fattr_dta; } |
213 |
next; |
214 |
} |
215 |
|
216 |
if ($fattr eq 'organism') { |
217 |
$org=$fattr_dta; |
218 |
#$org=~tr/"//d; #" |
219 |
} |
220 |
} # /attr=attrvalue parsing |
221 |
# store all attributes and their values -- for the current feature only |
222 |
#elsif ($fattr ne 'translation') { |
223 |
# push(@attrs, $fattr.'='.$fattr_dta); |
224 |
# } |
225 |
} #attribute parsing loop |
226 |
#&writeFeature($featname, $frange, $gname, @attrs); |
227 |
goto NEXTLINE if $endattr; |
228 |
next; |
229 |
}# FEATURES section reading |
230 |
|
231 |
if ($seqreading && m/^\s+\d+\s+(.+)/) { |
232 |
my $s=$1; |
233 |
$s=~tr/ \t\n//d; |
234 |
$fseq.=uc($s); |
235 |
} |
236 |
|
237 |
}#while input lines |
238 |
|
239 |
#close(FASTAOUT) if $fastaout; |
240 |
|
241 |
sub parseAttr { |
242 |
my ($fn, $a, $adta)=@_; |
243 |
#print STDERR "[[ parseAttr($fn, $a, $adta) ]]\n"; |
244 |
$adta=~s/^\s+//;$adta=~s/\s+$//; #trim |
245 |
#die("Invalid attribute string for $fn\:$a ($adta)\n") unless $adta=~m/^"/; |
246 |
if ($adta=~m/^"/) { |
247 |
while ($adta!~m/\"$/) { |
248 |
$_=<>; |
249 |
chomp; |
250 |
tr/ \t/ /s; #remove extra spaces |
251 |
$adta.=$_; |
252 |
} |
253 |
} |
254 |
$adta=~s/^\"//;$adta=~s/\"$//; #remove quotes |
255 |
$adta=~tr/\t \n\r/ /s; |
256 |
return ($a, $adta); |
257 |
} |
258 |
|
259 |
sub fastafmt { # (seqref, defline, linelen) |
260 |
my $seqr=shift(@_); |
261 |
my $defline=shift(@_); |
262 |
my $linelen=shift(@_) || 60;; |
263 |
my $rec; |
264 |
$rec=">$defline\n" if $defline; |
265 |
my $seqlen=length($$seqr); |
266 |
my $pos=0; |
267 |
while ($pos<$seqlen) { |
268 |
$rec.= substr($$seqr,$pos,$linelen)."\n"; |
269 |
$pos+=$linelen; |
270 |
} |
271 |
return $rec; |
272 |
} |