JAL-1807 Bob's JalviewJS prototype first commit
[jalviewjs.git] / src / com / stevesoft / pat / Replacer.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.MessageManager;
11
12 import com.stevesoft.pat.wrap.*;
13
14 /** Internally used class. */
15 class RegHolder
16 {
17   Regex me = null;
18
19   RegHolder prev = null;
20 }
21
22 /**
23  * Internally used class.
24  * 
25  * @see CodeRule
26  */
27 class CodeVal
28 {
29   int pos;
30
31   char code;
32
33   CodeVal(int p, char c)
34   {
35     pos = p;
36     code = c;
37   }
38
39   public String toString()
40   {
41     return "(" + pos + "," + code + ")";
42   }
43 }
44
45 /**
46  * To use this class, first use either the getReplacer() method from Transformer
47  * or Regex. You can then use replaceAll, replaceFirst, etc. methods on the
48  * Replacer in the same way that you can from either of those two classes.
49  * <p>
50  * The only potential difference between using the methods of Replacer to do the
51  * replacing is that Replacer remembers changes to the replacing object between
52  * calls to replaceAll, replaceFirst etc. For details, see the example file <a
53  * href="http://javaregex.com/code/trans3.java.html">trans3.java</a>.
54  * 
55  * @see com.stevesoft.pat.Transformer
56  * @see com.stevesoft.pat.Regex
57  */
58 public class Replacer
59 {
60   boolean first;
61
62   /** Instantiate a new Replacer. */
63   public Replacer()
64   {
65   }
66
67   public StringLike replaceFirstRegion(String s, Regex r, int start, int end)
68   {
69     return replaceFirstRegion(new StringWrap(s), r, start, end);
70   }
71
72   /**
73    * This method replaces the first occurence of the Regex in the String
74    * starting with position pos according to the Replacer rule of this object.
75    */
76   public StringLike replaceFirstRegion(StringLike s, Regex r, int start,
77           int end)
78   {
79     first = true;
80     rh.me = r;
81     rh.prev = null;
82     return dorep(s, start, end);
83   }
84
85   public StringLike replaceFirst(StringLike s)
86   {
87     return replaceFirstRegion(s, 0, s.length());
88   }
89
90   public StringLike replaceFirstFrom(StringLike s, int start)
91   {
92     return replaceFirstRegion(s, start, s.length());
93   }
94
95   public StringLike replaceFirstRegion(StringLike s, int start, int end)
96   {
97     first = true;
98     return dorep(s, start, end);
99   }
100
101   RegHolder rh = new RegHolder();
102
103   public StringLike replaceAllRegion(String s, Regex r, int start, int end)
104   {
105     return replaceAllRegion(new StringWrap(s), r, start, end);
106   }
107
108   /**
109    * This method replaces all occurences of the Regex in the String starting
110    * with postition pos according to the Replacer rule of this object.
111    */
112   public StringLike replaceAllRegion(StringLike s, Regex r, int start,
113           int end)
114   {
115     first = false;
116     // reset
117     rh.me = r;
118     rh.prev = null;
119     return dorep(s, start, end);
120   }
121
122   public StringLike replaceAll(StringLike s)
123   {
124     return replaceAllRegion(s, 0, s.length());
125   }
126
127   public StringLike replaceAllFrom(StringLike s, int start)
128   {
129     return replaceAllRegion(s, start, s.length());
130   }
131
132   public StringLike replaceAllRegion(StringLike s, int start, int end)
133   {
134     first = false;
135     return dorep(s, start, end);
136   }
137
138   public String replaceAll(String s)
139   {
140     return replaceAllRegion(new StringWrap(s), 0, s.length()).toString();
141   }
142
143   public String replaceAllFrom(String s, int start)
144   {
145     return replaceAllRegion(new StringWrap(s), start, s.length())
146             .toString();
147   }
148
149   public String replaceAllRegion(String s, int start, int end)
150   {
151     first = false;
152     return dorep(new StringWrap(s), start, end).toString();
153   }
154
155   final public boolean isSpecial(ReplaceRule x)
156   {
157     while (x != null)
158     {
159       if (x instanceof SpecialRule
160               || (x instanceof RuleHolder && ((RuleHolder) x).held instanceof SpecialRule))
161       {
162         return true;
163       }
164       x = x.next;
165     }
166     return false;
167   }
168
169   final public void apply1(RegRes rr)
170   {
171     rr.charsMatched_++;
172     apply(rr, null);
173     rr.charsMatched_--;
174   }
175
176   final StringLike dorep(StringLike s, int start, int end)
177   {
178     StringLike ret = s;
179     want_more_text = false;
180     lastMatchedTo = 0;
181     if (rh.me == null)
182     {
183       throw new NullPointerException(MessageManager.getString("exception.replace_null_regex_pointer"));
184     }
185     if (rh.me._searchLike(s, start, end))
186     {
187       int rmn = rh.me.matchedTo();
188       if (rh.me.charsMatched() == 0 && !isSpecial(rh.me.getReplaceRule()))
189       {
190         apply1(rh.me);
191         rmn++;
192       }
193       apply(rh.me);
194       if (!first)
195       {
196         for (int i = rmn; !want_more_text && rh.me._searchLike(s, i, end); i = rmn)
197         {
198           rmn = rh.me.matchedTo();
199           if (rh.me.charsMatched() == 0)
200           {
201             if (!isSpecial(rh.me.getReplaceRule()))
202             {
203               apply1(rh.me);
204             }
205             rmn++;
206           }
207           apply(rh.me);
208         }
209       }
210       ret = finish();
211       ret = ret == null ? s : ret;
212     }
213     return ret;
214   }
215
216   StringBufferLike sb = null;
217
218   StringLike src = null;
219
220   int pos = 0;
221
222   /**
223    * This method allows you to apply the results of several matches in a
224    * sequence to modify a String of text. Each call in the sequence must operate
225    * on the same piece of text and the matchedFrom() of each RegRes given to
226    * this method must be greater in value than the preceeding RegRes's
227    * matchedTo() value.
228    */
229   public void apply(RegRes r, ReplaceRule rp)
230   {
231     if (rp == null || (rp.next == null && rp instanceof AmpersandRule))
232     {
233       return;
234     }
235     if (r.didMatch())
236     {
237       if (src == null)
238       {
239         src = r.getStringLike();
240       }
241       if (sb == null)
242       {
243         sb = new StringBufferLike(src.newStringBufferLike());
244       }
245       int rmf = r.matchedFrom();
246       for (int ii = pos; ii < rmf; ii++)
247       {
248         sb.appendC(src.charAt(ii));
249       }
250
251       for (ReplaceRule x = rp; x != null; x = x.next)
252       {
253         x.apply(sb, r);
254         if (x instanceof SpecialRule)
255         {
256           if (x instanceof WantMoreTextReplaceRule && want_more_text_enable)
257           {
258             want_more_text = true;
259           }
260           else if (x instanceof PushRule)
261           {
262             RegHolder rh2 = new RegHolder();
263             rh2.me = ((PushRule) x).NewRule;
264             rh2.prev = rh;
265             rh = rh2;
266           }
267           else if (x instanceof PopRule)
268           {
269             if (rh.prev != null)
270             {
271               rh = rh.prev;
272             }
273           }
274           else if (x instanceof ChangeRule)
275           {
276             rh.me = ((ChangeRule) x).NewRule;
277           }
278         }
279       }
280       if (!want_more_text)
281       {
282         pos = r.matchedTo();
283       }
284     }
285   }
286
287   boolean want_more_text = false, want_more_text_enable = false;
288
289   public boolean WantMoreText()
290   {
291     return want_more_text;
292   }
293
294   /**
295    * Another form of apply, it is the same as apply(r,r.getReplaceRule()).
296    */
297   public void apply(Regex r)
298   {
299     apply(r, r.getReplaceRule());
300   }
301
302   /**
303    * This finishes the replacement, appending the right() part of the last
304    * RegRes given to substitute(RegRes). After this method is called, the
305    * Replace object is reset to perform another substitution. If no RegRes
306    * objects with a true didMatch are applied, this returns null.
307    */
308   public StringLike finish()
309   {
310     if (src == null)
311     {
312       return null;
313     }
314     // sb.append(src.substring(pos,src.length()));
315     int s_end = src.length();
316     for (int ii = pos; ii < s_end; ii++)
317     {
318       sb.appendC(src.charAt(ii));
319     }
320     src = null;
321     lastMatchedTo = pos;
322     pos = 0;
323     StringLike retstr = sb.toStringLike();
324     sb = null;
325     return retstr;
326   }
327
328   int lastMatchedTo = 0;
329
330   public Object clone()
331   {
332     Replacer r = new Replacer();
333     r.first = first;
334     r.src = src;
335     r.sb = sb;
336     r.pos = pos;
337     r.lastMatchedTo = lastMatchedTo;
338     r.want_more_text = want_more_text;
339     r.want_more_text_enable = want_more_text_enable;
340     r.rh.me = rh.me;
341     r.rh.prev = rh.prev;
342     return r;
343   }
344
345   public int lastMatchedTo()
346   {
347     return lastMatchedTo;
348   }
349
350   public Regex getRegex()
351   {
352     return rh.me;
353   }
354
355   public void setSource(StringLike sl)
356   {
357     src = sl;
358   }
359
360   public void setBuffer(StringBufferLike sbl)
361   {
362     sb = sbl;
363   }
364
365   public void setPos(int pos)
366   {
367     this.pos = pos;
368   }
369 }