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