JAL-3438 spotless for 2.11.2.0
[jalview.git] / src / com / stevesoft / pat / RegexWriter.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 java.io.IOException;
11 import java.io.StringWriter;
12 import java.io.Writer;
13
14 import com.stevesoft.pat.wrap.WriterWrap;
15
16 /**
17  * A basic extension of FilterWriter that uses Transformer to make replacements
18  * in data as it is written out. It attempts to transform a string whenever the
19  * End-of-Line (EOL) character is written (which is, by default, the carriage
20  * return '\n'). Only the transformed portion of the line is written out,
21  * allowing the RegexWriter to wait until a complete pattern is present before
22  * attempting to write out info. Until a pattern completes, data is stored in a
23  * StringBuffer -- which can be accessed through the length() and charAt()
24  * methods of this class.
25  * <p>
26  * Note a subtlety here -- while a Transformer normally matches at higher
27  * priority against the pattern added to it first, this will not necessarily be
28  * true when a multi-line match is in progress because one of the complete
29  * multi-line patterns may not be completely loaded in RegexWriter's buffer. For
30  * this reason, the Transformer class is equipped with a way to add a pattern
31  * and replacement rule in three pieces -- a beginning (once this matches,
32  * nothing else in the Transformer can match until the whole pattern matches),
33  * an ending (the whole pattern is a String formed by adding the beginning and
34  * ending), and a ReplaceRule.
35  * <p>
36  * An illustration of this is given in the this
37  * <a href="../test/trans.java">example.</a>
38  */
39 public class RegexWriter extends Writer
40 {
41   Replacer repr;
42
43   Writer w;
44
45   WriterWrap ww;
46
47   StringBuffer sb = new StringBuffer();
48
49   PartialBuffer wrap = new PartialBuffer(sb);
50
51   int pos, epos;
52
53   int interval = 128;
54
55   int bufferSize = 2 * 1024;
56
57   public RegexWriter(Transformer t, Writer w)
58   {
59     this.w = w;
60     ww = new WriterWrap(w);
61     repr = t.getReplacer();
62     repr.setBuffer(new StringBufferLike(ww));
63     repr.setSource(wrap);
64   }
65
66   public RegexWriter(Regex r, Writer w)
67   {
68     this.w = w;
69     ww = new WriterWrap(w);
70     repr = r.getReplacer();
71     repr.setBuffer(new StringBufferLike(ww));
72     repr.setSource(wrap);
73   }
74
75   char EOLchar = '\n';
76
77   /**
78    * This method no longer serves any purpose.
79    * 
80    * @deprecated
81    */
82   @Deprecated
83   public char getEOLchar()
84   {
85     return EOLchar;
86   }
87
88   /**
89    * This method no longer serves any purpose.
90    * 
91    * @deprecated
92    */
93   @Deprecated
94   public void setEOLchar(char c)
95   {
96     EOLchar = c;
97   }
98
99   int max_lines = 2;
100
101   /**
102    * This method no longer serves any purpose.
103    * 
104    * @deprecated
105    */
106   @Deprecated
107   public int getMaxLines()
108   {
109     return max_lines;
110   }
111
112   /**
113    * This method no longer serves any purpose.
114    * 
115    * @deprecated
116    */
117   @Deprecated
118   public void setMaxLines(int ml)
119   {
120     max_lines = ml;
121   }
122
123   void write() throws IOException
124   {
125     Regex rex = repr.getRegex();
126     int eposOld = epos;
127     if (rex.matchAt(wrap, epos) && !wrap.overRun)
128     {
129       while (pos < epos)
130       {
131         w.write(sb.charAt(pos++));
132       }
133       int to = rex.matchedTo();
134       repr.setPos(to);
135       repr.apply(rex, rex.getReplaceRule());
136       epos = pos = to;
137       if (epos == eposOld && epos < sb.length())
138       {
139         epos++;
140       }
141     }
142     else if (!wrap.overRun && epos < sb.length())
143     {
144       epos++;
145     }
146     while (pos < epos)
147     {
148       w.write(sb.charAt(pos++));
149     }
150     if (epos == sb.length())
151     {
152       sb.setLength(1);
153       pos = epos = 1;
154     }
155     else if (pos > bufferSize)
156     {
157       for (int i = bufferSize; i < sb.length(); i++)
158       {
159         sb.setCharAt(i - bufferSize, sb.charAt(i));
160       }
161       pos -= bufferSize;
162       epos -= bufferSize;
163       sb.setLength(sb.length() - bufferSize);
164     }
165   }
166
167   public void write(char[] ca, int b, int n) throws IOException
168   {
169     int m = b + n;
170     for (int i = b; i < m; i++)
171     {
172       sb.append(ca[i]);
173       if (sb.length() % interval == interval - 1)
174       {
175         wrap.overRun = false;
176         while (epos + interval < sb.length() && !wrap.overRun)
177         {
178           write();
179         }
180       }
181     }
182   }
183
184   public void flush() throws IOException
185   {
186   }
187
188   public void close() throws IOException
189   {
190     wrap.allowOverRun = false;
191     wrap.overRun = false;
192     while (epos < sb.length())
193     {
194       write();
195     }
196     write();
197     w.close();
198   }
199
200   /** The current size of the StringBuffer in use by RegexWriter. */
201   public int length()
202   {
203     return sb.length();
204   }
205
206   /** The character at location i in the StringBuffer. */
207   public char charAt(int i)
208   {
209     return sb.charAt(i);
210   }
211
212   /** Set the interval at which regex patterns are checked. */
213   public void setInterval(int i)
214   {
215     interval = i;
216   }
217
218   /** Get the interval at which regex matches are checked. */
219   public int getInterval()
220   {
221     return interval;
222   }
223
224   /** Get the buffer size. */
225   public int getBufferSize()
226   {
227     return bufferSize;
228   }
229
230   /** Set the buffer size. */
231   public void setBufferSize(int i)
232   {
233     bufferSize = i;
234   }
235
236   static void test(String re, String inp, int n) throws Exception
237   {
238     StringWriter sw = new StringWriter();
239     Regex rex = Regex.perlCode(re);
240     String res1 = rex.replaceAll(inp);
241     RegexWriter rw = new RegexWriter(rex, sw);
242     for (int i = 0; i < inp.length(); i++)
243     {
244       rw.write(inp.charAt(i));
245     }
246     rw.close();
247     String res2 = sw.toString();
248     if (!res1.equals(res2))
249     {
250       System.out.println("nmax=" + n);
251       System.out.println("re=" + re);
252       System.out.println("inp=" + inp);
253       System.out.println("res1=" + res1);
254       System.out.println("res2=" + res2);
255       System.exit(255);
256     }
257   }
258
259   public static void main(String[] args) throws Exception
260   {
261     for (int n = 1; n <= 1; n++)
262     {
263       test("s/x/y/", "-----x123456789", n);
264       test("s/x/y/", "x123456789", n);
265       test("s/x/y/", "-----x", n);
266       test("s/x.*?x/y/", ".xx..x..x...x...x....x....x", n);
267       test("s/x.*x/[$&]/", "--x........x--xx", n);
268       test("s/x.*x/[$&]/", "--x........x------", n);
269       test("s/.$/a/m", "bb\nbbb\nbbbb\nbbbbb\nbbbbbb\nbbbbbbbbbbbb", n);
270       test("s/.$/a/", "123", n);
271       test("s/.$/a/", "bb\nbbb\nbbbb\nbbbbb\nbbbbbb\nbb", n);
272       test("s/^./a/", "bb\nbbb\nbbbb\nbbbbb\nbbbbbb\nbb", n);
273       test("s/$/a/", "bbb", n);
274       test("s/^/a/", "bbb", n);
275       test("s/^/a/", "", n);
276       test("s{.*}{N}", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", n);
277       test("s/.{0,7}/y/", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", n);
278       test("s/x/$&/", "xxx", n);
279     }
280     System.out.println("Success!!!");
281   }
282 }