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