Graphical bits moved into files to save jar size
[jalview.git] / src / com / stevesoft / pat / Replacer.java
1 //\r
2 // This software is now distributed according to\r
3 // the Lesser Gnu Public License.  Please see\r
4 // http://www.gnu.org/copyleft/lesser.txt for\r
5 // the details.\r
6 //    -- Happy Computing!\r
7 //\r
8 package com.stevesoft.pat;\r
9 \r
10 import com.stevesoft.pat.wrap.StringWrap;\r
11 \r
12 /** Internally used class. */\r
13 class RegHolder {\r
14     Regex me = null;\r
15     RegHolder prev = null;\r
16 }\r
17 \r
18 /** Internally used class.\r
19   * @see CodeRule\r
20   */\r
21 class CodeVal {\r
22     int pos;\r
23     char code;\r
24     CodeVal(int p,char c) {\r
25         pos = p;\r
26         code = c;\r
27     }\r
28     public String toString() {\r
29         return "("+pos+","+code+")";\r
30     }\r
31 }\r
32 \r
33 /**\r
34   To use this class, first use either the getReplacer() method from\r
35   Transformer or Regex.  You can then use replaceAll, replaceFirst,\r
36   etc. methods on the Replacer in the same way that you can from\r
37   either of those two classes.\r
38   <p>\r
39   The only potential difference between using the methods of\r
40   Replacer to do the replacing is that Replacer remembers changes\r
41   to the replacing object between calls to replaceAll, replaceFirst\r
42   etc.  For details, see the example file\r
43   <a href="http://javaregex.com/code/trans3.java.html">trans3.java</a>.\r
44   @see com.stevesoft.pat.Transformer\r
45   @see com.stevesoft.pat.Regex\r
46 */\r
47 public class Replacer {\r
48     boolean first;\r
49 \r
50     /** Instantiate a new Replacer. */\r
51     public Replacer() {}\r
52 \r
53     public StringLike replaceFirstRegion(String s,Regex r,\r
54         int start,int end) {\r
55         return replaceFirstRegion(new StringWrap(s),r,start,end);\r
56     }\r
57     /** This method replaces the first occurence of the Regex in the\r
58         String starting with position pos\r
59         according to the Replacer rule of this object. */\r
60     public StringLike replaceFirstRegion(StringLike s,Regex r,\r
61         int start,int end) {\r
62         first = true;\r
63         rh.me = r;\r
64         rh.prev = null;\r
65         return dorep(s,start,end);\r
66     }\r
67     public StringLike replaceFirst(StringLike s) {\r
68         return replaceFirstRegion(s,0,s.length());\r
69     }\r
70     public StringLike replaceFirstFrom(StringLike s,int start) {\r
71         return replaceFirstRegion(s,start,s.length());\r
72     }\r
73     public StringLike replaceFirstRegion(StringLike s,int start,int end) {\r
74         first = true;\r
75         return dorep(s,start,end);\r
76     }\r
77 \r
78     RegHolder rh = new RegHolder();\r
79 \r
80     public StringLike replaceAllRegion(String s,Regex r,\r
81         int start, int end) {\r
82         return replaceAllRegion(new StringWrap(s),r,start,end);\r
83     }\r
84     /** This method replaces all occurences of the Regex in the\r
85         String starting with postition pos\r
86         according to the Replacer rule of this object. */\r
87     public StringLike replaceAllRegion(StringLike s,Regex r,\r
88         int start,int end) {\r
89         first = false;\r
90         // reset\r
91         rh.me = r;\r
92         rh.prev = null;\r
93         return dorep(s,start,end);\r
94     }\r
95     public StringLike replaceAll(StringLike s) {\r
96         return replaceAllRegion(s,0,s.length());\r
97     }\r
98     public StringLike replaceAllFrom(StringLike s,int start) {\r
99         return replaceAllRegion(s,start,s.length());\r
100     }\r
101     public StringLike replaceAllRegion(StringLike s,int start,int end) {\r
102         first = false;\r
103         return dorep(s,start,end);\r
104     }\r
105 \r
106     public String replaceAll(String s) {\r
107         return replaceAllRegion(new StringWrap(s),0,s.length()).toString();\r
108     }\r
109     public String replaceAllFrom(String s,int start) {\r
110         return replaceAllRegion(new StringWrap(s),start,s.length()).toString();\r
111     }\r
112     public String replaceAllRegion(String s,int start,int end) {\r
113         first = false;\r
114         return dorep(new StringWrap(s),start,end).toString();\r
115     }\r
116 \r
117     final public boolean isSpecial(ReplaceRule x) {\r
118         while(x != null) {\r
119             if(x instanceof SpecialRule\r
120                     || (x instanceof RuleHolder && ((RuleHolder)x).held instanceof SpecialRule))\r
121                 return true;\r
122             x = x.next;\r
123         }\r
124         return false;\r
125     }\r
126     final public void apply1(RegRes rr) {\r
127         rr.charsMatched_++;\r
128         apply(rr,null);\r
129         rr.charsMatched_--;\r
130     }\r
131 \r
132     final StringLike dorep(StringLike s,int start,int end) {\r
133         StringLike ret = s;\r
134         want_more_text = false;\r
135         lastMatchedTo = 0;\r
136         if(rh.me == null)\r
137             throw new NullPointerException("Replacer has null Regex pointer");\r
138         if(rh.me._search(s,start,end)) {\r
139             int rmn = rh.me.matchedTo();\r
140             if(rh.me.charsMatched()==0 && !isSpecial(rh.me.getReplaceRule())) {\r
141                 apply1(rh.me);\r
142                 rmn++;\r
143             }\r
144             apply(rh.me);\r
145             if(!first)\r
146                 for(int i=rmn;\r
147                         !want_more_text && rh.me._search(s,i,end);i=rmn) {\r
148                     rmn = rh.me.matchedTo();\r
149                     if(rh.me.charsMatched()==0) {\r
150                         if(!isSpecial(rh.me.getReplaceRule()))\r
151                             apply1(rh.me);\r
152                         rmn++;\r
153                     }\r
154                     apply(rh.me);\r
155                 }\r
156             ret = finish();\r
157             ret = ret == null ? s : ret;\r
158         }\r
159         return ret;\r
160     }\r
161 \r
162     StringBufferLike sb = null;\r
163     StringLike src = null;\r
164     int pos = 0;\r
165     /** This method allows you to apply the results of several\r
166         matches in a sequence to modify a String of text.  Each\r
167         call in the sequence must operate on the same piece of\r
168         text and the matchedFrom() of each RegRes given to this\r
169         method must be greater in value than the preceeding\r
170         RegRes's matchedTo() value.\r
171         */\r
172     public void apply(RegRes r,ReplaceRule rp) {\r
173         if(rp==null ||(rp.next == null && rp instanceof AmpersandRule))\r
174             return;\r
175         if(r.didMatch()) {\r
176             if(src == null)\r
177                 src = r.getStringLike();\r
178             if(sb == null)\r
179                 sb = new StringBufferLike(src.newStringBufferLike());\r
180             int rmf = r.matchedFrom();\r
181             for(int ii=pos;ii<rmf;ii++)\r
182               sb.append(src.charAt(ii));\r
183 \r
184             for(ReplaceRule x=rp;x != null;x=x.next) {\r
185                 x.apply(sb,r);\r
186                 if(x instanceof SpecialRule) {\r
187                     if(x instanceof WantMoreTextReplaceRule\r
188                             && want_more_text_enable)\r
189                         want_more_text = true;\r
190                     else if(x instanceof PushRule) {\r
191                         RegHolder rh2 = new RegHolder();\r
192                         rh2.me = ( (PushRule)x ).NewRule;\r
193                         rh2.prev = rh;\r
194                         rh = rh2;\r
195                     } else if(x instanceof PopRule) {\r
196                         if(rh.prev != null)\r
197                             rh = rh.prev;\r
198                     } else if(x instanceof ChangeRule) {\r
199                         rh.me = ( (ChangeRule) x).NewRule;\r
200                     }\r
201                 }\r
202             }\r
203             if(!want_more_text)\r
204                 pos = r.matchedTo();\r
205         }\r
206     }\r
207     boolean want_more_text = false, want_more_text_enable = false;\r
208     public boolean WantMoreText() { return want_more_text; }\r
209     /** Another form of apply, it is the same as\r
210         apply(r,r.getReplaceRule()). */\r
211     public void apply(Regex r) { apply(r,r.getReplaceRule()); }\r
212 \r
213     /** This finishes the replacement, appending the right() part of\r
214         the last RegRes given to substitute(RegRes).  After this method\r
215         is called, the Replace object is reset to perform another\r
216         substitution. If no RegRes objects with a true didMatch are\r
217         applied, this returns null. */\r
218     public StringLike finish() {\r
219         if(src==null)\r
220             return null;\r
221         //sb.append(src.substring(pos,src.length()));\r
222         int s_end = src.length();\r
223         for(int ii=pos;ii<s_end;ii++)\r
224           sb.append(src.charAt(ii));\r
225         src = null;\r
226         lastMatchedTo = pos;\r
227         pos = 0;\r
228         StringLike retstr = sb.toStringLike();\r
229         sb = null;\r
230         return retstr;\r
231     }\r
232     int lastMatchedTo = 0;\r
233     public Object clone() {\r
234         Replacer r = new Replacer();\r
235         r.first = first;\r
236         r.src = src;\r
237         r.sb = sb;\r
238         r.pos = pos;\r
239         r.lastMatchedTo = lastMatchedTo;\r
240         r.want_more_text = want_more_text;\r
241         r.want_more_text_enable = want_more_text_enable;\r
242         r.rh.me = rh.me;\r
243         r.rh.prev = rh.prev;\r
244         return r;\r
245     }\r
246     public int lastMatchedTo() { return lastMatchedTo; }\r
247     public Regex getRegex() {\r
248       return rh.me;\r
249     }\r
250     public void setSource(StringLike sl) {\r
251       src = sl;\r
252     }\r
253     public void setBuffer(StringBufferLike sbl) {\r
254       sb = sbl;\r
255     }\r
256     public void setPos(int pos) {\r
257       this.pos = pos;\r
258     }\r
259 }\r