Formatting
[jalview.git] / src / jalview / io / NewickFile.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4  *\r
5  * This program is free software; you can redistribute it and/or\r
6  * modify it under the terms of the GNU General Public License\r
7  * as published by the Free Software Foundation; either version 2\r
8  * of the License, or (at your option) any later version.\r
9  *\r
10  * This program is distributed in the hope that it will be useful,\r
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13  * GNU General Public License for more details.\r
14  *\r
15  * You should have received a copy of the GNU General Public License\r
16  * along with this program; if not, write to the Free Software\r
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
18  */\r
19 \r
20 // NewickFile.java\r
21 // Tree I/O\r
22 // http://evolution.genetics.washington.edu/phylip/newick_doc.html\r
23 // TODO: Implement Basic NHX tag parsing and preservation\r
24 // TODO: http://evolution.genetics.wustl.edu/eddy/forester/NHX.html\r
25 // TODO: Extended SequenceNodeI to hold parsed NHX strings\r
26 package jalview.io;\r
27 \r
28 import java.io.*;\r
29 \r
30 import jalview.datamodel.*;\r
31 \r
32 /**\r
33  * DOCUMENT ME!\r
34  *\r
35  * @author $author$\r
36  * @version $Revision$\r
37  */\r
38 public class NewickFile\r
39     extends FileParse\r
40 {\r
41   SequenceNode root;\r
42   private boolean HasBootstrap = false;\r
43   private boolean HasDistances = false;\r
44   private boolean RootHasDistance = false;\r
45 \r
46   // File IO Flags\r
47   boolean ReplaceUnderscores = false;\r
48   boolean printRootInfo = false;\r
49   private com.stevesoft.pat.Regex[] NodeSafeName = new com.stevesoft.pat.Regex[]\r
50       {\r
51       new com.stevesoft.pat.Regex().perlCode("m/[\\[,:'()]/"), // test for requiring quotes\r
52       new com.stevesoft.pat.Regex().perlCode("s/'/''/"), // escaping quote characters\r
53       new com.stevesoft.pat.Regex().perlCode("s/\\/w/_/") // unqoted whitespace transformation\r
54   };\r
55   char QuoteChar = '\'';\r
56 \r
57   /**\r
58    * Creates a new NewickFile object.\r
59    *\r
60    * @param inStr DOCUMENT ME!\r
61    *\r
62    * @throws IOException DOCUMENT ME!\r
63    */\r
64   public NewickFile(String inStr)\r
65       throws IOException\r
66   {\r
67     super(inStr, "Paste");\r
68   }\r
69 \r
70   /**\r
71    * Creates a new NewickFile object.\r
72    *\r
73    * @param inFile DOCUMENT ME!\r
74    * @param type DOCUMENT ME!\r
75    *\r
76    * @throws IOException DOCUMENT ME!\r
77    */\r
78   public NewickFile(String inFile, String type)\r
79       throws IOException\r
80   {\r
81     super(inFile, type);\r
82   }\r
83 \r
84   /**\r
85    * Creates a new NewickFile object.\r
86    *\r
87    * @param newtree DOCUMENT ME!\r
88    */\r
89   public NewickFile(SequenceNode newtree)\r
90   {\r
91     root = newtree;\r
92   }\r
93 \r
94   /**\r
95    * Creates a new NewickFile object.\r
96    *\r
97    * @param newtree DOCUMENT ME!\r
98    * @param bootstrap DOCUMENT ME!\r
99    */\r
100   public NewickFile(SequenceNode newtree, boolean bootstrap)\r
101   {\r
102     HasBootstrap = bootstrap;\r
103     root = newtree;\r
104   }\r
105 \r
106   /**\r
107    * Creates a new NewickFile object.\r
108    *\r
109    * @param newtree DOCUMENT ME!\r
110    * @param bootstrap DOCUMENT ME!\r
111    * @param distances DOCUMENT ME!\r
112    */\r
113   public NewickFile(SequenceNode newtree, boolean bootstrap, boolean distances)\r
114   {\r
115     root = newtree;\r
116     HasBootstrap = bootstrap;\r
117     HasDistances = distances;\r
118   }\r
119 \r
120   /**\r
121    * Creates a new NewickFile object.\r
122    *\r
123    * @param newtree DOCUMENT ME!\r
124    * @param bootstrap DOCUMENT ME!\r
125    * @param distances DOCUMENT ME!\r
126    * @param rootdistance DOCUMENT ME!\r
127    */\r
128   public NewickFile(SequenceNode newtree, boolean bootstrap,\r
129                     boolean distances, boolean rootdistance)\r
130   {\r
131     root = newtree;\r
132     HasBootstrap = bootstrap;\r
133     HasDistances = distances;\r
134     RootHasDistance = rootdistance;\r
135   }\r
136 \r
137   /**\r
138    * DOCUMENT ME!\r
139    *\r
140    * @param Error DOCUMENT ME!\r
141    * @param Er DOCUMENT ME!\r
142    * @param r DOCUMENT ME!\r
143    * @param p DOCUMENT ME!\r
144    * @param s DOCUMENT ME!\r
145    *\r
146    * @return DOCUMENT ME!\r
147    */\r
148   private String ErrorStringrange(String Error, String Er, int r, int p,\r
149                                   String s)\r
150   {\r
151     return ( (Error == null) ? "" : Error) + Er + " at position " + p +\r
152         " ( " +\r
153         s.substring( ( (p - r) < 0) ? 0 : (p - r),\r
154                     ( (p + r) > s.length()) ? s.length() : (p + r)) + " )\n";\r
155   }\r
156 \r
157   // @tree annotations\r
158   // These are set automatically by the reader\r
159   public boolean HasBootstrap()\r
160   {\r
161     return HasBootstrap;\r
162   }\r
163 \r
164   /**\r
165    * DOCUMENT ME!\r
166    *\r
167    * @return DOCUMENT ME!\r
168    */\r
169   public boolean HasDistances()\r
170   {\r
171     return HasDistances;\r
172   }\r
173 \r
174   public boolean HasRootDistance()\r
175   {\r
176     return RootHasDistance;\r
177   }\r
178 \r
179   /**\r
180    * DOCUMENT ME!\r
181    *\r
182    * @throws IOException DOCUMENT ME!\r
183    */\r
184   public void parse()\r
185       throws IOException\r
186   {\r
187     String nf;\r
188 \r
189     { // fill nf with complete tree file\r
190 \r
191       StringBuffer file = new StringBuffer();\r
192 \r
193       while ( (nf = nextLine()) != null)\r
194       {\r
195         file.append(nf);\r
196       }\r
197 \r
198       nf = file.toString();\r
199     }\r
200 \r
201     root = new SequenceNode();\r
202 \r
203     SequenceNode realroot = null;\r
204     SequenceNode c = root;\r
205 \r
206     int d = -1;\r
207     int cp = 0;\r
208     //int flen = nf.length();\r
209 \r
210     String Error = null;\r
211     String nodename = null;\r
212 \r
213     float DefDistance = (float) 0.001; // @param Default distance for a node - very very small\r
214     int DefBootstrap = 0; // @param Default bootstrap for a node\r
215 \r
216     float distance = DefDistance;\r
217     int bootstrap = DefBootstrap;\r
218 \r
219     boolean ascending = false; // flag indicating that we are leaving the current node\r
220 \r
221     com.stevesoft.pat.Regex majorsyms = new com.stevesoft.pat.Regex(\r
222         "[(\\['),;]");\r
223 \r
224     while (majorsyms.searchFrom(nf, cp) && (Error == null))\r
225     {\r
226       int fcp = majorsyms.matchedFrom();\r
227 \r
228       switch (nf.charAt(fcp))\r
229       {\r
230         case '[': // Comment or structured/extended NH format info\r
231 \r
232           com.stevesoft.pat.Regex comment = new com.stevesoft.pat.Regex(\r
233               "]");\r
234 \r
235           if (comment.searchFrom(nf, fcp))\r
236           {\r
237             // Skip the comment field\r
238             cp = 1 + comment.matchedFrom();\r
239           }\r
240           else\r
241           {\r
242             Error = ErrorStringrange(Error, "Unterminated comment", 3,\r
243                                      fcp, nf);\r
244           }\r
245 \r
246           ;\r
247 \r
248           break;\r
249 \r
250         case '(':\r
251 \r
252           // ascending should not be set\r
253           // New Internal node\r
254           if (ascending)\r
255           {\r
256             Error = ErrorStringrange(Error, "Unexpected '('", 7, fcp, nf);\r
257 \r
258             continue;\r
259           }\r
260 \r
261           ;\r
262           d++;\r
263 \r
264           if (c.right() == null)\r
265           {\r
266             c.setRight(new SequenceNode(null, c, null, DefDistance,\r
267                                         DefBootstrap, false));\r
268             c = (SequenceNode) c.right();\r
269           }\r
270           else\r
271           {\r
272             if (c.left() != null)\r
273             {\r
274               // Dummy node for polytomy - keeps c.left free for new node\r
275               SequenceNode tmpn = new SequenceNode(null, c, null, 0,\r
276                   0, true);\r
277               tmpn.SetChildren(c.left(), c.right());\r
278               c.setRight(tmpn);\r
279             }\r
280 \r
281             c.setLeft(new SequenceNode(null, c, null, DefDistance,\r
282                                        DefBootstrap, false));\r
283             c = (SequenceNode) c.left();\r
284           }\r
285 \r
286           if (realroot == null)\r
287           {\r
288             realroot = c;\r
289           }\r
290 \r
291           nodename = null;\r
292           distance = DefDistance;\r
293           bootstrap = DefBootstrap;\r
294           cp = fcp + 1;\r
295 \r
296           break;\r
297 \r
298           // Deal with quoted fields\r
299         case '\'':\r
300 \r
301           com.stevesoft.pat.Regex qnodename = new com.stevesoft.pat.Regex(\r
302               "([^']|'')+'");\r
303 \r
304           if (qnodename.searchFrom(nf, fcp))\r
305           {\r
306             int nl = qnodename.stringMatched().length();\r
307             nodename = new String(qnodename.stringMatched().substring(0,\r
308                 nl - 1));\r
309             cp = fcp + nl + 1;\r
310           }\r
311           else\r
312           {\r
313             Error = ErrorStringrange(Error,\r
314                                      "Unterminated quotes for nodename", 7, fcp,\r
315                                      nf);\r
316           }\r
317 \r
318           break;\r
319 \r
320         case ';':\r
321 \r
322           if (d != -1)\r
323           {\r
324             Error = ErrorStringrange(Error,\r
325                                      "Wayward semicolon (depth=" + d + ")", 7,\r
326                                      fcp, nf);\r
327           }\r
328 \r
329           // cp advanced at the end of default\r
330         default:\r
331 \r
332           // Parse simpler field strings\r
333           String fstring = nf.substring(cp, fcp);\r
334           com.stevesoft.pat.Regex uqnodename = new com.stevesoft.pat.Regex(\r
335               "\\b([^' :;\\](),]+)");\r
336           com.stevesoft.pat.Regex nbootstrap = new com.stevesoft.pat.Regex(\r
337               "\\S+([0-9+]+)\\S*:");\r
338           com.stevesoft.pat.Regex ndist = new com.stevesoft.pat.Regex(\r
339               ":([-0-9Ee.+]+)");\r
340 \r
341           if (uqnodename.search(fstring) &&\r
342               ( (uqnodename.matchedFrom(1) == 0) ||\r
343                (fstring.charAt(uqnodename.matchedFrom(1) - 1) != ':'))) // JBPNote HACK!\r
344           {\r
345             if (nodename == null)\r
346             {\r
347               if (ReplaceUnderscores)\r
348               {\r
349                 nodename = uqnodename.stringMatched(1).replace('_',\r
350                     ' ');\r
351               }\r
352               else\r
353               {\r
354                 nodename = uqnodename.stringMatched(1);\r
355               }\r
356             }\r
357             else\r
358             {\r
359               Error = ErrorStringrange(Error,\r
360                                        "File has broken algorithm - overwritten nodename",\r
361                                        10, fcp, nf);\r
362             }\r
363           }\r
364 \r
365           if (nbootstrap.search(fstring) &&\r
366               (nbootstrap.matchedFrom(1) > (uqnodename.matchedFrom(1) +\r
367                                             uqnodename.stringMatched().length())))\r
368           {\r
369             try\r
370             {\r
371               bootstrap = (new Integer(nbootstrap.stringMatched(1))).intValue();\r
372               HasBootstrap = true;\r
373             }\r
374             catch (Exception e)\r
375             {\r
376               Error = ErrorStringrange(Error,\r
377                                        "Can't parse bootstrap value", 4,\r
378                                        cp + nbootstrap.matchedFrom(), nf);\r
379             }\r
380           }\r
381 \r
382           boolean nodehasdistance = false;\r
383 \r
384           if (ndist.search(fstring))\r
385           {\r
386             try\r
387             {\r
388               distance = (new Float(ndist.stringMatched(1))).floatValue();\r
389               HasDistances = true;\r
390               nodehasdistance = true;\r
391             }\r
392             catch (Exception e)\r
393             {\r
394               Error = ErrorStringrange(Error,\r
395                                        "Can't parse node distance value", 7,\r
396                                        cp + ndist.matchedFrom(), nf);\r
397             }\r
398           }\r
399 \r
400           if (ascending)\r
401           {\r
402             // Write node info here\r
403             c.setName(nodename);\r
404             // Trees without distances still need a render distance\r
405             c.dist = (HasDistances) ? distance : DefDistance;\r
406             // be consistent for internal bootstrap defaults too\r
407             c.setBootstrap( (HasBootstrap) ? bootstrap : DefBootstrap);\r
408             if (c == realroot)\r
409             {\r
410               RootHasDistance = nodehasdistance; // JBPNote This is really UGLY!!! Ensure root node gets its given distance\r
411             }\r
412           }\r
413           else\r
414           {\r
415             // Find a place to put the leaf\r
416             SequenceNode newnode = new SequenceNode(null, c, nodename,\r
417                 (HasDistances) ? distance : DefDistance,\r
418                 (HasBootstrap) ? bootstrap : DefBootstrap, false);\r
419 \r
420             if (c.right() == null)\r
421             {\r
422               c.setRight(newnode);\r
423             }\r
424             else\r
425             {\r
426               if (c.left() == null)\r
427               {\r
428                 c.setLeft(newnode);\r
429               }\r
430               else\r
431               {\r
432                 // Insert a dummy node for polytomy\r
433                 // dummy nodes have distances\r
434                 SequenceNode newdummy = new SequenceNode(null, c,\r
435                     null, (HasDistances ? 0 : DefDistance), 0, true);\r
436                 newdummy.SetChildren(c.left(), newnode);\r
437                 c.setLeft(newdummy);\r
438               }\r
439             }\r
440           }\r
441 \r
442           if (ascending)\r
443           {\r
444             // move back up the tree from preceding closure\r
445             c = c.AscendTree();\r
446 \r
447             if ( (d > -1) && (c == null))\r
448             {\r
449               Error = ErrorStringrange(Error,\r
450                                        "File broke algorithm: Lost place in tree (is there an extra ')' ?)",\r
451                                        7, fcp, nf);\r
452             }\r
453           }\r
454 \r
455           if (nf.charAt(fcp) == ')')\r
456           {\r
457             d--;\r
458             ascending = true;\r
459           }\r
460           else\r
461           {\r
462             if (nf.charAt(fcp) == ',')\r
463             {\r
464               if (ascending)\r
465               {\r
466                 ascending = false;\r
467               }\r
468               else\r
469               {\r
470                 // Just advance focus, if we need to\r
471                 if ( (c.left() != null) && (!c.left().isLeaf()))\r
472                 {\r
473                   c = (SequenceNode) c.left();\r
474                 }\r
475               }\r
476             }\r
477 \r
478             // else : We do nothing if ';' is encountered.\r
479           }\r
480 \r
481           // Reset new node properties to obvious fakes\r
482           nodename = null;\r
483           distance = DefDistance;\r
484           bootstrap = DefBootstrap;\r
485 \r
486           cp = fcp + 1;\r
487       }\r
488     }\r
489 \r
490     if (Error != null)\r
491     {\r
492       throw (new IOException("NewickFile: " + Error + "\n"));\r
493     }\r
494 \r
495     root = (SequenceNode) root.right().detach(); // remove the imaginary root.\r
496 \r
497     if (!RootHasDistance)\r
498     {\r
499       root.dist = (HasDistances) ? 0 : DefDistance;\r
500     }\r
501   }\r
502 \r
503   /**\r
504    * DOCUMENT ME!\r
505    *\r
506    * @return DOCUMENT ME!\r
507    */\r
508   public SequenceNode getTree()\r
509   {\r
510     return root;\r
511   }\r
512 \r
513   /**\r
514    * Generate a newick format tree according to internal flags\r
515    * for bootstraps, distances and root distances.\r
516    *\r
517    * @return new hampshire tree in a single line\r
518    */\r
519   public String print()\r
520   {\r
521     synchronized (this)\r
522     {\r
523       StringBuffer tf = new StringBuffer();\r
524       print(tf, root);\r
525 \r
526       return (tf.append(";").toString());\r
527     }\r
528   }\r
529 \r
530   /**\r
531    *\r
532    *\r
533    * Generate a newick format tree according to internal flags\r
534    * for distances and root distances and user specificied writing of\r
535    * bootstraps.\r
536    * @param withbootstraps controls if bootstrap values are explicitly written.\r
537    *\r
538    * @return new hampshire tree in a single line\r
539    */\r
540   public String print(boolean withbootstraps)\r
541   {\r
542     synchronized (this)\r
543     {\r
544       boolean boots = this.HasBootstrap;\r
545       this.HasBootstrap = withbootstraps;\r
546 \r
547       String rv = print();\r
548       this.HasBootstrap = boots;\r
549 \r
550       return rv;\r
551     }\r
552   }\r
553 \r
554   /**\r
555    *\r
556    * Generate newick format tree according to internal flags\r
557    * for writing root node distances.\r
558    *\r
559    * @param withbootstraps explicitly write bootstrap values\r
560    * @param withdists explicitly write distances\r
561    *\r
562    * @return new hampshire tree in a single line\r
563    */\r
564   public String print(boolean withbootstraps, boolean withdists)\r
565   {\r
566     synchronized (this)\r
567     {\r
568       boolean dists = this.HasDistances;\r
569       this.HasDistances = withdists;\r
570 \r
571       String rv = print(withbootstraps);\r
572       this.HasDistances = dists;\r
573 \r
574       return rv;\r
575     }\r
576   }\r
577 \r
578   /**\r
579    * Generate newick format tree according to user specified flags\r
580    *\r
581    * @param withbootstraps explicitly write bootstrap values\r
582    * @param withdists explicitly write distances\r
583    * @param printRootInfo explicitly write root distance\r
584    *\r
585    * @return new hampshire tree in a single line\r
586    */\r
587   public String print(boolean withbootstraps, boolean withdists,\r
588                       boolean printRootInfo)\r
589   {\r
590     synchronized (this)\r
591     {\r
592       boolean rootinfo = printRootInfo;\r
593       this.printRootInfo = printRootInfo;\r
594 \r
595       String rv = print(withbootstraps, withdists);\r
596       this.printRootInfo = rootinfo;\r
597 \r
598       return rv;\r
599     }\r
600   }\r
601 \r
602   /**\r
603    * DOCUMENT ME!\r
604    *\r
605    * @return DOCUMENT ME!\r
606    */\r
607   char getQuoteChar()\r
608   {\r
609     return QuoteChar;\r
610   }\r
611 \r
612   /**\r
613    * DOCUMENT ME!\r
614    *\r
615    * @param c DOCUMENT ME!\r
616    *\r
617    * @return DOCUMENT ME!\r
618    */\r
619   char setQuoteChar(char c)\r
620   {\r
621     char old = QuoteChar;\r
622     QuoteChar = c;\r
623 \r
624     return old;\r
625   }\r
626 \r
627   /**\r
628    * DOCUMENT ME!\r
629    *\r
630    * @param name DOCUMENT ME!\r
631    *\r
632    * @return DOCUMENT ME!\r
633    */\r
634   private String nodeName(String name)\r
635   {\r
636     if (NodeSafeName[0].search(name))\r
637     {\r
638       return QuoteChar + NodeSafeName[1].replaceAll(name) + QuoteChar;\r
639     }\r
640     else\r
641     {\r
642       return NodeSafeName[2].replaceAll(name);\r
643     }\r
644   }\r
645 \r
646   /**\r
647    * DOCUMENT ME!\r
648    *\r
649    * @param c DOCUMENT ME!\r
650    *\r
651    * @return DOCUMENT ME!\r
652    */\r
653   private String printNodeField(SequenceNode c)\r
654   {\r
655     return ( (c.getName() == null) ? "" : nodeName(c.getName())) +\r
656         ( (HasBootstrap)\r
657          ? ( (c.getBootstrap() > -1) ? (" " + c.getBootstrap()) : "") : "") +\r
658         ( (HasDistances) ? (":" + c.dist) : "");\r
659   }\r
660 \r
661   /**\r
662    * DOCUMENT ME!\r
663    *\r
664    * @param root DOCUMENT ME!\r
665    *\r
666    * @return DOCUMENT ME!\r
667    */\r
668   private String printRootField(SequenceNode root)\r
669   {\r
670     return (printRootInfo)\r
671         ? ( ( (root.getName() == null) ? "" : nodeName(root.getName())) +\r
672            ( (HasBootstrap)\r
673             ? ( (root.getBootstrap() > -1) ? (" " + root.getBootstrap()) : "") :\r
674             "") +\r
675            ( (RootHasDistance) ? (":" + root.dist) : "")) : "";\r
676   }\r
677 \r
678   // Non recursive call deals with root node properties\r
679   public void print(StringBuffer tf, SequenceNode root)\r
680   {\r
681     if (root != null)\r
682     {\r
683       if (root.isLeaf() && printRootInfo)\r
684       {\r
685         tf.append(printRootField(root));\r
686       }\r
687       else\r
688       {\r
689         if (root.isDummy())\r
690         {\r
691           _print(tf, (SequenceNode) root.right());\r
692           _print(tf, (SequenceNode) root.left());\r
693         }\r
694         else\r
695         {\r
696           tf.append("(");\r
697           _print(tf, (SequenceNode) root.right());\r
698 \r
699           if (root.left() != null)\r
700           {\r
701             tf.append(",");\r
702           }\r
703 \r
704           _print(tf, (SequenceNode) root.left());\r
705           tf.append(")" + printRootField(root));\r
706         }\r
707       }\r
708     }\r
709   }\r
710 \r
711   // Recursive call for non-root nodes\r
712   public void _print(StringBuffer tf, SequenceNode c)\r
713   {\r
714     if (c != null)\r
715     {\r
716       if (c.isLeaf())\r
717       {\r
718         tf.append(printNodeField(c));\r
719       }\r
720       else\r
721       {\r
722         if (c.isDummy())\r
723         {\r
724           _print(tf, (SequenceNode) c.left());\r
725           if (c.left() != null)\r
726           {\r
727             tf.append(",");\r
728           }\r
729           _print(tf, (SequenceNode) c.right());\r
730         }\r
731         else\r
732         {\r
733           tf.append("(");\r
734           _print(tf, (SequenceNode) c.right());\r
735 \r
736           if (c.left() != null)\r
737           {\r
738             tf.append(",");\r
739           }\r
740 \r
741           _print(tf, (SequenceNode) c.left());\r
742           tf.append(")" + printNodeField(c));\r
743         }\r
744       }\r
745     }\r
746   }\r
747 \r
748   // Test\r
749   public static void main(String[] args)\r
750   {\r
751     try\r
752     {\r
753       if (args == null || args.length != 1)\r
754       {\r
755         System.err.println(\r
756             "Takes one argument - file name of a newick tree file.");\r
757         System.exit(0);\r
758       }\r
759 \r
760       File fn = new File(args[0]);\r
761 \r
762       StringBuffer newickfile = new StringBuffer();\r
763       BufferedReader treefile = new BufferedReader(new FileReader(fn));\r
764       String l;\r
765 \r
766       while ( (l = treefile.readLine()) != null)\r
767       {\r
768         newickfile.append(l);\r
769       }\r
770 \r
771       treefile.close();\r
772       System.out.println("Read file :\n");\r
773 \r
774       NewickFile trf = new NewickFile(args[0], "File");\r
775       trf.parse();\r
776       System.out.println("Original file :\n");\r
777 \r
778       com.stevesoft.pat.Regex nonl = new com.stevesoft.pat.Regex("\n+", "");\r
779       System.out.println(nonl.replaceAll(newickfile.toString()) + "\n");\r
780 \r
781       System.out.println("Parsed file.\n");\r
782       System.out.println("Default output type for original input.\n");\r
783       System.out.println(trf.print());\r
784       System.out.println("Without bootstraps.\n");\r
785       System.out.println(trf.print(false));\r
786       System.out.println("Without distances.\n");\r
787       System.out.println(trf.print(true, false));\r
788       System.out.println("Without bootstraps but with distanecs.\n");\r
789       System.out.println(trf.print(false, true));\r
790       System.out.println("Without bootstraps or distanecs.\n");\r
791       System.out.println(trf.print(false, false));\r
792       System.out.println("With bootstraps and with distances.\n");\r
793       System.out.println(trf.print(true, true));\r
794     }\r
795     catch (java.io.IOException e)\r
796     {\r
797       System.err.println("Exception\n" + e);\r
798       e.printStackTrace();\r
799     }\r
800   }\r
801 }\r