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