0b863e0cd974961e8c235ffbfe405620c936a7af
[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: https://sites.google.com/site/cmzmasek/home/software/forester
26
27 package org.forester.io.parsers;
28
29 import java.io.BufferedReader;
30 import java.io.ByteArrayInputStream;
31 import java.io.File;
32 import java.io.FileInputStream;
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.io.InputStreamReader;
36 import java.util.ArrayList;
37 import java.util.List;
38 import java.util.regex.Matcher;
39 import java.util.regex.Pattern;
40
41 import org.forester.msa.BasicMsa;
42 import org.forester.msa.Msa;
43 import org.forester.msa.MsaFormatException;
44 import org.forester.sequence.BasicSequence;
45 import org.forester.sequence.MolecularSequence;
46
47 public class FastaParser {
48
49     private static final Pattern NAME_REGEX      = Pattern.compile( "^\\s*>\\s*(.+)" );
50     private static final Pattern SEQ_REGEX       = Pattern.compile( "^\\s*(.+)" );
51     private static final Pattern ANYTHING_REGEX  = Pattern.compile( "[\\d\\s]+" );
52     //>gi|71834668|ref|NP_001025424.1| Bcl2 [Danio rerio]
53     public static final Pattern  FASTA_DESC_LINE = Pattern
54                                                          .compile( ">?\\s*([^|]+)\\|([^|]+)\\S*\\s+(.+)\\s+\\[(.+)\\]" );
55
56     public static void main( final String[] args ) {
57         final String a = ">gi|71834668|ref|NP_001025424.1| Bcl2 [Danio rerio]";
58         final Matcher name_m = FASTA_DESC_LINE.matcher( a );
59         if ( name_m.lookingAt() ) {
60             System.out.println();
61             System.out.println( name_m.group( 1 ) );
62             System.out.println( name_m.group( 2 ) );
63             System.out.println( name_m.group( 3 ) );
64             System.out.println( name_m.group( 4 ) );
65         }
66         else {
67             System.out.println( "Does not match." );
68         }
69     }
70
71     static public boolean isLikelyFasta( final File f ) throws IOException {
72         return isLikelyFasta( new FileInputStream( f ) );
73     }
74
75     static public boolean isLikelyFasta( final InputStream is ) throws IOException {
76         final BufferedReader reader = new BufferedReader( new InputStreamReader( is, "UTF-8" ) );
77         String line = null;
78         while ( ( line = reader.readLine() ) != null ) {
79             final boolean is_name_line = NAME_REGEX.matcher( line ).lookingAt();
80             if ( canIgnore( line, true, false ) ) {
81                 continue;
82             }
83             else if ( is_name_line ) {
84                 reader.close();
85                 return true;
86             }
87             else if ( SEQ_REGEX.matcher( line ).lookingAt() ) {
88                 reader.close();
89                 return false;
90             }
91         }
92         reader.close();
93         return false;
94     }
95
96     static public Msa parseMsa( final File f ) throws IOException {
97         return parseMsa( new FileInputStream( f ) );
98     }
99
100     static public Msa parseMsa( final InputStream is ) throws IOException {
101         return BasicMsa.createInstance( parse( is ) );
102     }
103
104     static public Msa parseMsa( final String s ) throws IOException {
105         return parseMsa( s.getBytes() );
106     }
107
108     static public Msa parseMsa( final byte[] bytes ) throws IOException {
109         return parseMsa( new ByteArrayInputStream( bytes ) );
110     }
111
112     static public List<MolecularSequence> parse( final File f ) throws IOException {
113         return parse( new FileInputStream( f ) );
114     }
115
116     static public List<MolecularSequence> parse( final InputStream is ) throws IOException {
117         final BufferedReader reader = new BufferedReader( new InputStreamReader( is, "UTF-8" ) );
118         String line = null;
119         int line_counter = 0;
120         boolean saw_first_seq = false;
121         StringBuilder current_seq = null;
122         StringBuilder name = null;
123         final List<StringBuilder[]> temp_msa = new ArrayList<StringBuilder[]>();
124         while ( ( line = reader.readLine() ) != null ) {
125             ++line_counter;
126             final Matcher name_m = NAME_REGEX.matcher( line );
127             final boolean is_name_line = name_m.lookingAt();
128             if ( canIgnore( line, saw_first_seq, is_name_line ) ) {
129                 continue;
130             }
131             final Matcher seq_m = SEQ_REGEX.matcher( line );
132             if ( is_name_line ) {
133                 saw_first_seq = true;
134                 addSeq( name, current_seq, temp_msa );
135                 name = new StringBuilder( name_m.group( 1 ).trim() );
136                 current_seq = new StringBuilder();
137             }
138             else if ( seq_m.lookingAt() ) {
139                 if ( name.length() < 1 ) {
140                     reader.close();
141                     throw new MsaFormatException( "illegally formatted fasta msa (line: " + line_counter + "):\n\""
142                             + trim( line ) + "\"" );
143                 }
144                 current_seq.append( seq_m.group( 1 ).replaceAll( "\\s+", "" ) );
145             }
146             else {
147                 reader.close();
148                 throw new MsaFormatException( "illegally formatted fasta msa (line: " + line_counter + "):\n\""
149                         + trim( line ) + "\"" );
150             }
151         }
152         addSeq( name, current_seq, temp_msa );
153         reader.close();
154         final List<MolecularSequence> seqs = new ArrayList<MolecularSequence>();
155         for( int i = 0; i < temp_msa.size(); ++i ) {
156             seqs.add( BasicSequence.createAaSequence( temp_msa.get( i )[ 0 ].toString(),
157                                                       temp_msa.get( i )[ 1 ].toString() ) );
158         }
159         return seqs;
160     }
161
162     static private boolean canIgnore( final String line, final boolean saw_first_seq, final boolean is_name_line ) {
163         if ( ( line.length() < 1 ) || ANYTHING_REGEX.matcher( line ).matches() ) {
164             return true;
165         }
166         if ( !saw_first_seq && !is_name_line ) {
167             return true;
168         }
169         return false;
170     }
171
172     private static void addSeq( final StringBuilder name, final StringBuilder seq, final List<StringBuilder[]> temp_msa ) {
173         if ( ( name != null ) && ( seq != null ) && ( name.length() > 0 ) && ( seq.length() > 0 ) ) {
174             final StringBuilder[] ary = new StringBuilder[ 2 ];
175             ary[ 0 ] = name;
176             ary[ 1 ] = seq;
177             temp_msa.add( ary );
178         }
179     }
180
181     private static String trim( final String line ) {
182         if ( line.length() > 100 ) {
183             return line.substring( 0, 100 ) + " ...";
184         }
185         return line;
186     }
187 }