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