1 /*******************************************************************************
2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $(date) The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
20 *******************************************************************************/
22 // This software is now distributed according to
23 // the Lesser Gnu Public License. Please see
24 // http://www.gnu.org/copyleft/lesser.txt for
26 // -- Happy Computing!
28 package com.stevesoft.pat;
30 import java.io.IOException;
31 import java.io.StringWriter;
32 import java.io.Writer;
34 import com.stevesoft.pat.wrap.WriterWrap;
37 * A basic extension of FilterWriter that uses Transformer to make replacements
38 * in data as it is written out. It attempts to transform a string whenever the
39 * End-of-Line (EOL) character is written (which is, by default, the carriage
40 * return '\n'). Only the transformed portion of the line is written out,
41 * allowing the RegexWriter to wait until a complete pattern is present before
42 * attempting to write out info. Until a pattern completes, data is stored in a
43 * StringBuffer -- which can be accessed through the length() and charAt()
44 * methods of this class.
46 * Note a subtlety here -- while a Transformer normally matches at higher
47 * priority against the pattern added to it first, this will not necessarily be
48 * true when a multi-line match is in progress because one of the complete
49 * multi-line patterns may not be completely loaded in RegexWriter's buffer. For
50 * this reason, the Transformer class is equipped with a way to add a pattern
51 * and replacement rule in three pieces -- a beginning (once this matches,
52 * nothing else in the Transformer can match until the whole pattern matches),
53 * an ending (the whole pattern is a String formed by adding the beginning and
54 * ending), and a ReplaceRule.
56 * An illustration of this is given in the this <a
57 * href="../test/trans.java">example.</a>
59 public class RegexWriter extends Writer
67 StringBuffer sb = new StringBuffer();
69 PartialBuffer wrap = new PartialBuffer(sb);
75 int bufferSize = 2 * 1024;
77 public RegexWriter(Transformer t, Writer w)
80 ww = new WriterWrap(w);
81 repr = t.getReplacer();
82 repr.setBuffer(new StringBufferLike(ww));
86 public RegexWriter(Regex r, Writer w)
89 ww = new WriterWrap(w);
90 repr = r.getReplacer();
91 repr.setBuffer(new StringBufferLike(ww));
98 * This method no longer serves any purpose.
103 public char getEOLchar()
109 * This method no longer serves any purpose.
114 public void setEOLchar(char c)
122 * This method no longer serves any purpose.
127 public int getMaxLines()
133 * This method no longer serves any purpose.
138 public void setMaxLines(int ml)
143 void write() throws IOException
145 Regex rex = repr.getRegex();
147 if (rex.matchAt(wrap, epos) && !wrap.overRun)
151 w.write(sb.charAt(pos++));
153 int to = rex.matchedTo();
155 repr.apply(rex, rex.getReplaceRule());
157 if (epos == eposOld && epos < sb.length())
162 else if (!wrap.overRun && epos < sb.length())
168 w.write(sb.charAt(pos++));
170 if (epos == sb.length())
175 else if (pos > bufferSize)
177 for (int i = bufferSize; i < sb.length(); i++)
179 sb.setCharAt(i - bufferSize, sb.charAt(i));
183 sb.setLength(sb.length() - bufferSize);
187 public void write(char[] ca, int b, int n) throws IOException
190 for (int i = b; i < m; i++)
193 if (sb.length() % interval == interval - 1)
195 wrap.overRun = false;
196 while (epos + interval < sb.length() && !wrap.overRun)
204 public void flush() throws IOException
208 public void close() throws IOException
210 wrap.allowOverRun = false;
211 wrap.overRun = false;
212 while (epos < sb.length())
220 /** The current size of the StringBuffer in use by RegexWriter. */
226 /** The character at location i in the StringBuffer. */
227 public char charAt(int i)
232 /** Set the interval at which regex patterns are checked. */
233 public void setInterval(int i)
238 /** Get the interval at which regex matches are checked. */
239 public int getInterval()
244 /** Get the buffer size. */
245 public int getBufferSize()
250 /** Set the buffer size. */
251 public void setBufferSize(int i)
256 static void test(String re, String inp, int n) throws Exception
258 StringWriter sw = new StringWriter();
259 Regex rex = Regex.perlCode(re);
260 String res1 = rex.replaceAll(inp);
261 RegexWriter rw = new RegexWriter(rex, sw);
262 for (int i = 0; i < inp.length(); i++)
264 rw.write(inp.charAt(i));
267 String res2 = sw.toString();
268 if (!res1.equals(res2))
270 System.out.println("nmax=" + n);
271 System.out.println("re=" + re);
272 System.out.println("inp=" + inp);
273 System.out.println("res1=" + res1);
274 System.out.println("res2=" + res2);
279 public static void main(String[] args) throws Exception
281 for (int n = 1; n <= 1; n++)
283 test("s/x/y/", "-----x123456789", n);
284 test("s/x/y/", "x123456789", n);
285 test("s/x/y/", "-----x", n);
286 test("s/x.*?x/y/", ".xx..x..x...x...x....x....x", n);
287 test("s/x.*x/[$&]/", "--x........x--xx", n);
288 test("s/x.*x/[$&]/", "--x........x------", n);
289 test("s/.$/a/m", "bb\nbbb\nbbbb\nbbbbb\nbbbbbb\nbbbbbbbbbbbb", n);
290 test("s/.$/a/", "123", n);
291 test("s/.$/a/", "bb\nbbb\nbbbb\nbbbbb\nbbbbbb\nbb", n);
292 test("s/^./a/", "bb\nbbb\nbbbb\nbbbbb\nbbbbbb\nbb", n);
293 test("s/$/a/", "bbb", n);
294 test("s/^/a/", "bbb", n);
295 test("s/^/a/", "", n);
296 test("s{.*}{N}", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", n);
297 test("s/.{0,7}/y/", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", n);
298 test("s/x/$&/", "xxx", n);
300 System.out.println("Success!!!");