clean up
[jalview.git] / forester / java / src / org / forester / io / parsers / FastaParser.java
1 // $Id:
2 //
3 // forester -- software libraries and applications
4 // for genomics and evolutionary biology research.
5 //
6 // Copyright (C) 2010 Christian M Zmasek
7 // Copyright (C) 2010 Sanford-Burnham Medical Research Institute
8 // All rights reserved
9 //
10 // This library is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU Lesser General Public
12 // License as published by the Free Software Foundation; either
13 // version 2.1 of the License, or (at your option) any later version.
14 //
15 // This library is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 // Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public
21 // License along with this library; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 //
24 // Contact: phylosoft @ gmail . com
25 // WWW: www.phylosoft.org/forester
26
27 package org.forester.io.parsers;
28
29 import java.io.BufferedReader;
30 import java.io.ByteArrayInputStream;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.io.InputStreamReader;
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.regex.Matcher;
37 import java.util.regex.Pattern;
38
39 import org.forester.msa.BasicMsa;
40 import org.forester.msa.Msa;
41 import org.forester.msa.MsaFormatException;
42 import org.forester.phylogeny.Phylogeny;
43 import org.forester.phylogeny.PhylogenyNode;
44 import org.forester.phylogeny.data.Accession;
45 import org.forester.phylogeny.iterators.PhylogenyNodeIterator;
46 import org.forester.sequence.BasicSequence;
47 import org.forester.sequence.Sequence;
48 import org.forester.util.ForesterUtil;
49
50 public class FastaParser {
51
52     private static final Pattern NAME_REGEX      = Pattern.compile( "^\\s*>\\s*(.+)" );
53     private static final Pattern SEQ_REGEX       = Pattern.compile( "^\\s*(.+)" );
54     private static final Pattern ANYTHING_REGEX  = Pattern.compile( "[\\d\\s]+" );
55     //>gi|71834668|ref|NP_001025424.1| Bcl2 [Danio rerio]
56     private static final Pattern FASTA_DESC_LINE = Pattern
57                                                          .compile( ">?\\s*([^|]+)\\|([^|]+)\\S*\\s+(.+)\\s+\\[(.+)\\]" );
58
59     public static void main( final String[] args ) {
60         final String a = ">gi|71834668|ref|NP_001025424.1| Bcl2 [Danio rerio]";
61         final Matcher name_m = FASTA_DESC_LINE.matcher( a );
62         if ( name_m.lookingAt() ) {
63             System.out.println();
64             System.out.println( name_m.group( 1 ) );
65             System.out.println( name_m.group( 2 ) );
66             System.out.println( name_m.group( 3 ) );
67             System.out.println( name_m.group( 4 ) );
68         }
69         else {
70             System.out.println( "Does not match." );
71         }
72     }
73
74     static public boolean isLikelyFasta( final InputStream is ) throws IOException {
75         final BufferedReader reader = new BufferedReader( new InputStreamReader( is, "UTF-8" ) );
76         String line = null;
77         while ( ( line = reader.readLine() ) != null ) {
78             final boolean is_name_line = NAME_REGEX.matcher( line ).lookingAt();
79             if ( canIgnore( line, true, false ) ) {
80                 continue;
81             }
82             else if ( is_name_line ) {
83                 reader.close();
84                 return true;
85             }
86             else if ( SEQ_REGEX.matcher( line ).lookingAt() ) {
87                 reader.close();
88                 return false;
89             }
90         }
91         reader.close();
92         return false;
93     }
94
95     static public Msa parseMsa( final InputStream is ) throws IOException {
96         return BasicMsa.createInstance( parse( is ) );
97     }
98
99     static public Msa parseMsa( final String s ) throws IOException {
100         return parseMsa( s.getBytes() );
101     }
102
103     static public Msa parseMsa( final byte[] bytes ) throws IOException {
104         return parseMsa( new ByteArrayInputStream( bytes ) );
105     }
106
107     static public List<Sequence> parse( final InputStream is ) throws IOException {
108         final BufferedReader reader = new BufferedReader( new InputStreamReader( is, "UTF-8" ) );
109         String line = null;
110         int line_counter = 0;
111         boolean saw_first_seq = false;
112         StringBuilder current_seq = null;
113         StringBuilder name = null;
114         final List<StringBuilder[]> temp_msa = new ArrayList<StringBuilder[]>();
115         while ( ( line = reader.readLine() ) != null ) {
116             ++line_counter;
117             final Matcher name_m = NAME_REGEX.matcher( line );
118             final boolean is_name_line = name_m.lookingAt();
119             if ( canIgnore( line, saw_first_seq, is_name_line ) ) {
120                 continue;
121             }
122             final Matcher seq_m = SEQ_REGEX.matcher( line );
123             if ( is_name_line ) {
124                 saw_first_seq = true;
125                 addSeq( name, current_seq, temp_msa );
126                 name = new StringBuilder( name_m.group( 1 ).trim() );
127                 current_seq = new StringBuilder();
128             }
129             else if ( seq_m.lookingAt() ) {
130                 if ( name.length() < 1 ) {
131                     reader.close();
132                     throw new MsaFormatException( "illegally formatted fasta msa (line: " + line_counter + "):\n\""
133                             + trim( line ) + "\"" );
134                 }
135                 current_seq.append( seq_m.group( 1 ).replaceAll( "\\s+", "" ) );
136             }
137             else {
138                 reader.close();
139                 throw new MsaFormatException( "illegally formatted fasta msa (line: " + line_counter + "):\n\""
140                         + trim( line ) + "\"" );
141             }
142         }
143         addSeq( name, current_seq, temp_msa );
144         reader.close();
145         final List<Sequence> seqs = new ArrayList<Sequence>();
146         for( int i = 0; i < temp_msa.size(); ++i ) {
147             seqs.add( BasicSequence.createAaSequence( temp_msa.get( i )[ 0 ].toString(),
148                                                       temp_msa.get( i )[ 1 ].toString() ) );
149         }
150         return seqs;
151     }
152
153     static private boolean canIgnore( final String line, final boolean saw_first_seq, final boolean is_name_line ) {
154         if ( ( line.length() < 1 ) || ANYTHING_REGEX.matcher( line ).matches() ) {
155             return true;
156         }
157         if ( !saw_first_seq && !is_name_line ) {
158             return true;
159         }
160         return false;
161     }
162
163     private static void addSeq( final StringBuilder name, final StringBuilder seq, final List<StringBuilder[]> temp_msa ) {
164         if ( ( name != null ) && ( seq != null ) && ( name.length() > 0 ) && ( seq.length() > 0 ) ) {
165             final StringBuilder[] ary = new StringBuilder[ 2 ];
166             ary[ 0 ] = name;
167             ary[ 1 ] = seq;
168             temp_msa.add( ary );
169         }
170     }
171
172     private static String trim( final String line ) {
173         if ( line.length() > 100 ) {
174             return line.substring( 0, 100 ) + " ...";
175         }
176         return line;
177     }
178
179     public static void extractFastaInformation( final Phylogeny phy ) {
180         for( final PhylogenyNodeIterator iter = phy.iteratorExternalForward(); iter.hasNext(); ) {
181             final PhylogenyNode node = iter.next();
182             if ( !ForesterUtil.isEmpty( node.getName() ) ) {
183                 final Matcher name_m = FASTA_DESC_LINE.matcher( node.getName() );
184                 if ( name_m.lookingAt() ) {
185                     System.out.println();
186                     // System.out.println( name_m.group( 1 ) );
187                     // System.out.println( name_m.group( 2 ) );
188                     // System.out.println( name_m.group( 3 ) );
189                     // System.out.println( name_m.group( 4 ) );
190                     final String acc_source = name_m.group( 1 );
191                     final String acc = name_m.group( 2 );
192                     final String seq_name = name_m.group( 3 );
193                     final String tax_sn = name_m.group( 4 );
194                     if ( !ForesterUtil.isEmpty( acc_source ) && !ForesterUtil.isEmpty( acc ) ) {
195                         ForesterUtil.ensurePresenceOfSequence( node );
196                         node.getNodeData().getSequence( 0 ).setAccession( new Accession( acc, acc_source ) );
197                     }
198                     if ( !ForesterUtil.isEmpty( seq_name ) ) {
199                         ForesterUtil.ensurePresenceOfSequence( node );
200                         node.getNodeData().getSequence( 0 ).setName( seq_name );
201                     }
202                     if ( !ForesterUtil.isEmpty( tax_sn ) ) {
203                         ForesterUtil.ensurePresenceOfTaxonomy( node );
204                         node.getNodeData().getTaxonomy( 0 ).setScientificName( tax_sn );
205                     }
206                 }
207             }
208         }
209     }
210 }