Copyright test
[jalview.git] / src / com / stevesoft / pat / Transformer.java
1 /*******************************************************************************
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $(date) The Jalview Authors
4  *
5  * This file is part of Jalview.
6  *  
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *   
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  *******************************************************************************/
21 //
22 // This software is now distributed according to
23 // the Lesser Gnu Public License.  Please see
24 // http://www.gnu.org/copyleft/lesser.txt for
25 // the details.
26 //    -- Happy Computing!
27 //
28 package com.stevesoft.pat;
29
30 import jalview.util.MessageManager;
31
32 import com.stevesoft.pat.wrap.StringWrap;
33
34 /**
35  * Replacement rule used by the Transformer.
36  * 
37  * @see com.stevesoft.pat.Transformer
38  */
39 class TransRepRule extends ReplaceRule
40 {
41   Transformer t;
42
43   TransRepRule(Transformer t)
44   {
45     this.t = t;
46   }
47
48   public String toString1()
49   {
50     return "";
51   }
52
53   public Object clone1()
54   {
55     return new TransRepRule(t);
56   }
57
58   public void apply(StringBufferLike sb, RegRes rr)
59   {
60     // get the ReplaceRule of the Regex that matched.
61     next = t.tp.ra[t.tp.pn].getReplaceRule();
62   }
63 }
64
65 /**
66  * Sometimes you want to replace a whole bunch of things that might occur within
67  * a single line of text. One efficient way to do this, both in terms of
68  * performance and programming ease, is with Transformer. The Transformer
69  * contains an array of Regex's and uses the Regex that matches earliest within
70  * the text to do the replacing, if two Regex's match at the same time it uses
71  * the one put in the Transformer first.
72  * <p>
73  * This feature can be used to prevent transformations from occurring in certain
74  * regions. For example, if I add the rule s'//.*'$&' and then add the rule
75  * s/hello/goodbye/ the Transformer will replace "hello" with "goodbye" except
76  * when it occurs inside a double-slash style of comment. The transformation on
77  * the comment goes first, does nothing, and precludes transformation on the
78  * same region of text as the s/hello/goodbye/ rule.
79  * <p>
80  * So far, at least, this class does not have the capability of turning into a
81  * giant robot :-)
82  */
83 public class Transformer
84 {
85   TransPat tp;
86
87   Regex rp = new Regex();
88
89   boolean auto_optimize;
90
91   /**
92    * Get a replacer to that works with the current Regex.
93    * 
94    * @see com.stevesoft.pat.Replacer
95    */
96   public Replacer getReplacer()
97   {
98     return rp.getReplacer();
99   }
100
101   /** Instantiate a new Transformer object. */
102   public Transformer(boolean auto)
103   {
104     auto_optimize = auto;
105     tp = new TransPat();
106     rp.setReplaceRule(new TransRepRule(this));
107     rp.thePattern = tp;
108   }
109
110   /** Add a new Regex to the set of Regex's. */
111   public void add(Regex r)
112   {
113     if (auto_optimize)
114     {
115       r.optimize();
116     }
117     tp.ra[tp.ra_len++] = r;
118     if (tp.ra.length == tp.ra_len)
119     {
120       Regex[] ra2 = new Regex[tp.ra_len + 10];
121       for (int i = 0; i < tp.ra_len; i++)
122       {
123         ra2[i] = tp.ra[i];
124       }
125       tp.ra = ra2;
126     }
127     rp.numSubs_ = r.numSubs_ > rp.numSubs_ ? r.numSubs_ : rp.numSubs_;
128   }
129
130   /** Returns the number of Regex's in this Transformer. */
131   public int patterns()
132   {
133     return tp.ra_len;
134   }
135
136   /** Get the Regex at position i in this Transformer. */
137   public Regex getRegexAt(int i)
138   {
139     if (i >= tp.ra_len)
140     {
141       throw new ArrayIndexOutOfBoundsException("i=" + i + ">=" + patterns());
142     }
143     if (i < 0)
144     {
145       throw new ArrayIndexOutOfBoundsException("i=" + i + "< 0");
146     }
147     return tp.ra[i];
148   }
149
150   /** Set the Regex at position i in this Transformer. */
151   public void setRegexAt(Regex rx, int i)
152   {
153     if (i >= tp.ra_len)
154     {
155       throw new ArrayIndexOutOfBoundsException("i=" + i + ">=" + patterns());
156     }
157     if (i < 0)
158     {
159       throw new ArrayIndexOutOfBoundsException("i=" + i + "< 0");
160     }
161     tp.ra[i] = rx;
162   }
163
164   /**
165    * Add a new Regex by calling Regex.perlCode
166    * 
167    * @see com.stevesoft.pat.Regex#perlCode(java.lang.String)
168    */
169   public void add(String rs)
170   {
171     Regex r = Regex.perlCode(rs);
172     if (r == null)
173     {
174       throw new NullPointerException(MessageManager.formatMessage(
175               "exception.bad_pattern_to_regex_perl_code",
176               new String[] { rs }));
177     }
178     add(r);
179   }
180
181   /**
182    * Add an array of Strings (which will be converted to Regex's via the
183    * Regex.perlCode method.
184    * 
185    * @see com.stevesoft.pat.Regex#perlCode(java.lang.String)
186    */
187   public void add(String[] array)
188   {
189     for (int i = 0; i < array.length; i++)
190     {
191       add(array[i]);
192     }
193   }
194
195   /** Replace all matches in the current String. */
196   public String replaceAll(String s)
197   {
198     return dorep(s, 0, s.length());
199   }
200
201   public StringLike replaceAll(StringLike s)
202   {
203     return dorep(s, 0, s.length());
204   }
205
206   /** Replace all matching patterns beginning at position start. */
207   public String replaceAllFrom(String s, int start)
208   {
209     return dorep(s, start, s.length());
210   }
211
212   /**
213    * Replace all matching patterns beginning between the positions start and end
214    * inclusive.
215    */
216   public String replaceAllRegion(String s, int start, int end)
217   {
218     return dorep(s, start, end);
219   }
220
221   Replacer repr = new Replacer();
222
223   final StringLike dorep(StringLike s, int start, int end)
224   {
225     StringLike tfmd = repr.replaceAllRegion(s, rp, start, end);
226     tp.lastMatchedTo = repr.lastMatchedTo;
227     return tfmd;
228   }
229
230   final String dorep(String s, int start, int end)
231   {
232     return dorep(new StringWrap(s), start, end).toString();
233   }
234
235   /** Replace the first matching pattern in String s. */
236   public String replaceFirst(String s)
237   {
238     return dorep(s, 0, s.length());
239   }
240
241   /**
242    * Replace the first matching pattern after position start in String s.
243    */
244   public String replaceFirstFrom(String s, int start)
245   {
246     return dorep(s, start, s.length());
247   }
248
249   /**
250    * Replace the first matching pattern that begins between start and end
251    * inclusive.
252    */
253   public String replaceFirstRegion(String s, int start, int end)
254   {
255     return dorep(s, start, end);
256   }
257 }