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