JAL-2114 parser + tests for GenBank location descriptors
[jalview.git] / src / jalview / util / DnaUtils.java
1 package jalview.util;
2
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.List;
6
7 public class DnaUtils
8 {
9
10   /**
11    * Parses an ENA/GenBank format location specifier and returns a list of
12    * [start, end] ranges. Returns null if not able to parse.
13    * 
14    * @param location
15    * @return
16    * @see http://www.insdc.org/files/feature_table.html#3.4
17    */
18   public static List<int[]> parseLocation(String location)
19   {
20     if (location.startsWith("join("))
21     {
22       return parseJoin(location);
23     }
24     else if (location.startsWith("complement("))
25     {
26       return parseComplement(location);
27     }
28     String errorMessage = "Unable to process location specifier: "
29             + location;
30     if (location.startsWith("order("))
31     {
32       System.err.println(errorMessage);
33       return null;
34     }
35     String[] range = location.split("\\.\\.");
36     if (range.length == 2)
37     {
38       try
39       {
40         int start = Integer.valueOf(range[0]);
41         int end = Integer.valueOf(range[1]);
42         return Collections.singletonList(new int[] { start, end });
43       } catch (NumberFormatException e)
44       {
45         /*
46          * could be a location like <1..888 or 1..>888
47          */
48         System.err.println(errorMessage);
49         return null;
50       }
51     }
52     else
53     {
54       /*
55        * could be a location like 102.110 or 123^124
56        */
57       System.err.println(errorMessage);
58       return null;
59     }
60   }
61
62   /**
63    * Parses a complement(locationSpec) into a list of start-end ranges
64    * 
65    * @param location
66    * @return
67    */
68   static List<int[]> parseComplement(String location)
69   {
70     /*
71      * take what is inside complement()
72      */
73     String toComplement = location.substring("complement(".length(),
74             location.length() - 1);
75     List<int[]> ranges = parseLocation(toComplement);
76     if (ranges == null)
77     {
78       /*
79        * something bad in there
80        */
81       return null;
82     }
83
84     /*
85      * reverse the order and direction of ranges
86      */
87     Collections.reverse(ranges);
88     for (int[] range : ranges)
89     {
90       int temp = range[0];
91       range[0] = range[1];
92       range[1] = temp;
93     }
94     return ranges;
95   }
96
97   /**
98    * Parses a join(loc1,loc2,...,locn) into a list of start-end ranges
99    * 
100    * @param location
101    * @return
102    */
103   static List<int[]> parseJoin(String location)
104   {
105     List<int[]> ranges = new ArrayList<int[]>();
106
107     /*
108      * take what is inside join()
109      */
110     String joinedLocs = location.substring("join(".length(),
111             location.length() - 1);
112     String[] locations = joinedLocs.split(",");
113     for (String loc : locations)
114     {
115       List<int[]> range = parseLocation(loc);
116       if (range == null)
117       {
118         /*
119          * something bad in there
120          */
121         return null;
122       }
123       else
124       {
125         ranges.addAll(range);
126       }
127     }
128     return ranges;
129   }
130
131 }