ensure successive matches to a regex have distinct annotation name (indice suffix...
[jalview.git] / src / jalview / io / StockholmFile.java
index dedbd44..ccbe818 100644 (file)
@@ -31,9 +31,15 @@ import jalview.datamodel.*;
 \r
 /**\r
  * This class is supposed to parse a Stockholm format file into Jalview\r
- * \r
+ * There are TODOs in this class: we do not know what the database source and\r
+ * version is for the file when parsing the #GS= AC tag which associates accessions\r
+ * with sequences. \r
+ * Database references are also not parsed correctly: a separate reference string\r
+ * parser must be added to parse the database reference form into Jalview's local\r
+ * representation.\r
  * @author bsb at sanger.ac.uk\r
- * @version 0.3\r
+ * @version 0.3 + jalview mods\r
+ * \r
  */\r
 public class StockholmFile extends AlignFile\r
 {\r
@@ -47,7 +53,10 @@ public class StockholmFile extends AlignFile
   {\r
     super(inFile, type);\r
   }\r
-\r
+  public StockholmFile(FileParse source) throws IOException\r
+  {\r
+    super(source);\r
+  }\r
   public void initData()\r
   {\r
     super.initData();\r
@@ -91,7 +100,7 @@ public class StockholmFile extends AlignFile
     rend = new Regex("\\/\\/"); // Find the end of an alignment\r
     p = new Regex("(\\S+)\\/(\\d+)\\-(\\d+)"); // split sequence id in\r
                                                 // id/from/to\r
-    s = new Regex("(\\S+)\\s+(\\w{2})\\s+(.*)"); // Parses annotation subtype\r
+    s = new Regex("(\\S+)\\s+(\\S*)\\s+(.*)"); // Parses annotation subtype\r
     r = new Regex("#=(G[FSRC]?)\\s+(.*)"); // Finds any annotation line\r
     x = new Regex("(\\S+)\\s+(\\S+)"); // split id from sequence\r
 \r
@@ -118,7 +127,7 @@ public class StockholmFile extends AlignFile
         {\r
           String acc = (String) accs.nextElement();\r
           // logger.debug("Processing sequence " + acc);\r
-          String seq = (String) seqs.get(acc);\r
+          String seq = (String) seqs.remove(acc);\r
           if (maxLength < seq.length())\r
           {\r
             maxLength = seq.length();\r
@@ -131,7 +140,7 @@ public class StockholmFile extends AlignFile
 \r
           if (seqAnn != null && seqAnn.containsKey(acc))\r
           {\r
-            accAnnotations = (Hashtable) seqAnn.get(acc);\r
+            accAnnotations = (Hashtable) seqAnn.remove(acc);\r
           }\r
 \r
           // Split accession in id and from/to\r
@@ -158,16 +167,15 @@ public class StockholmFile extends AlignFile
             {\r
               String src = dbr.substring(0, dbr.indexOf(";"));\r
               String acn = dbr.substring(dbr.indexOf(";") + 1);\r
-              DBRefEntry dbref = new DBRefEntry(jalview.util.DBRefUtils\r
-                      .getCanonicalName(src), acn, "");\r
-              seqO.addDBRef(dbref);\r
+              jalview.util.DBRefUtils.parseToDbRef(seqO, src, "0", acn);\r
+              //seqO.addDBRef(dbref);\r
             }\r
           }\r
           Hashtable features = null;\r
           // We need to adjust the positions of all features to account for gaps\r
           try\r
           {\r
-            features = (Hashtable) accAnnotations.get("features");\r
+            features = (Hashtable) accAnnotations.remove("features");\r
           } catch (java.lang.NullPointerException e)\r
           {\r
             // loggerwarn("Getting Features for " + acc + ": " +\r
@@ -177,6 +185,7 @@ public class StockholmFile extends AlignFile
           // if we have features\r
           if (features != null)\r
           {\r
+            int posmap[] = seqO.findPositionMap();\r
             Enumeration i = features.keys();\r
             while (i.hasMoreElements())\r
             {\r
@@ -185,8 +194,7 @@ public class StockholmFile extends AlignFile
               // TODO: parse out scores as annotation row\r
               // TODO: map coding region to core jalview feature types\r
               String type = i.nextElement().toString();\r
-              Hashtable content = (Hashtable) features.get(type);\r
-\r
+              Hashtable content = (Hashtable) features.remove(type);\r
               Enumeration j = content.keys();\r
               while (j.hasMoreElements())\r
               {\r
@@ -196,9 +204,9 @@ public class StockholmFile extends AlignFile
                 for (int k = 0; k < byChar.length; k++)\r
                 {\r
                   char c = byChar[k];\r
-                  if (!(c == ' ' || c == '_' || c == '-'))\r
+                  if (!(c == ' ' || c == '_' || c == '-' || c == '.')) // PFAM uses '.' for feature background\r
                   {\r
-                    int new_pos = seqO.findPosition(k);\r
+                    int new_pos = posmap[k]; // look up nearest seqeunce position to this column\r
                     SequenceFeature feat = new SequenceFeature(type, desc,\r
                             new_pos, new_pos, 0f, null);\r
 \r
@@ -208,12 +216,15 @@ public class StockholmFile extends AlignFile
               }\r
 \r
             }\r
-\r
+            \r
           }\r
+          // garbage collect\r
+          \r
           // logger.debug("Adding seq " + acc + " from " + start + " to " + end\r
           // + ": " + seq);\r
           this.seqs.addElement(seqO);\r
         }\r
+        return; // finished parsing this segment of source\r
       }\r
       else if (!r.search(line))\r
       {\r
@@ -365,14 +376,18 @@ public class StockholmFile extends AlignFile
           {\r
             String acc = s.stringMatched(1);\r
             String type = s.stringMatched(2);\r
-            String seq = s.stringMatched(3);\r
-            String description = new String();\r
-\r
+            String seq = new String(s.stringMatched(3));\r
+            String description = null;\r
             // Check for additional information about the current annotation\r
-            if (x.search(seq))\r
+            // We use a simple  string tokenizer here for speed\r
+            StringTokenizer sep = new StringTokenizer(seq," \t");\r
+            description = sep.nextToken();\r
+            if (sep.hasMoreTokens())\r
             {\r
-              description = x.stringMatched(1);\r
-              seq = x.stringMatched(2);\r
+              seq = sep.nextToken();\r
+            } else {\r
+              seq = description;\r
+              description = new String();\r
             }\r
             // sequence id with from-to fields\r
 \r
@@ -427,7 +442,8 @@ public class StockholmFile extends AlignFile
           }\r
           else\r
           {\r
-            throw new IOException("Error parsing " + line);\r
+            System.err.println("Warning - couldn't parse sequence annotation row line:\n"+line);\r
+            // throw new IOException("Error parsing " + line);\r
           }\r
         }\r
         else\r
@@ -464,18 +480,18 @@ public class StockholmFile extends AlignFile
     {\r
       String pos = annots.substring(i, i + 1);\r
       Annotation ann;\r
-      ann = new Annotation(pos, "", ' ', Float.NaN);\r
+      ann = new Annotation(pos, "", ' ', 0f); // 0f is 'valid' null - will not be written out \r
       if (ss)\r
       {\r
         ann.secondaryStructure = jalview.schemes.ResidueProperties\r
                 .getDssp3state(pos).charAt(0);\r
         if (ann.secondaryStructure == pos.charAt(0) || pos.charAt(0) == 'C')\r
         {\r
-          ann.displayCharacter = "";\r
+          ann.displayCharacter = ""; // null; // " ";\r
         }\r
         else\r
         {\r
-          ann.displayCharacter += " ";\r
+          ann.displayCharacter = " "+ann.displayCharacter;\r
         }\r
       }\r
 \r
@@ -493,7 +509,7 @@ public class StockholmFile extends AlignFile
     if (annot == null)\r
     {\r
       annot = new AlignmentAnnotation(type, type, els);\r
-      annotation.add(annot);\r
+      annotation.addElement(annot);\r
     }\r
     else\r
     {\r