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