needed for applet search
[jalview.git] / src / com / stevesoft / pat / RegexWriter.java
diff --git a/src/com/stevesoft/pat/RegexWriter.java b/src/com/stevesoft/pat/RegexWriter.java
new file mode 100755 (executable)
index 0000000..008f6ac
--- /dev/null
@@ -0,0 +1,205 @@
+//\r
+// This software is now distributed according to\r
+// the Lesser Gnu Public License.  Please see\r
+// http://www.gnu.org/copyleft/lesser.txt for\r
+// the details.\r
+//    -- Happy Computing!\r
+//\r
+package com.stevesoft.pat;\r
+\r
+import java.io.*;\r
+import com.stevesoft.pat.wrap.*;\r
+\r
+/** A basic extension of FilterWriter that uses Transformer\r
+ to make replacements in data as it is written out.  It attempts\r
+ to transform a string whenever the End-of-Line (EOL) character\r
+ is written (which is, by default, the carriage return '\n').\r
+ Only the transformed portion of the line is written out, allowing\r
+ the RegexWriter to wait until a complete pattern is present before\r
+ attempting to write out info.  Until a pattern completes, data is\r
+ stored in a StringBuffer -- which can be accessed through the\r
+ length() and charAt() methods of this class.\r
+ <p>\r
+ Note a subtlety here -- while a Transformer normally matches\r
+ at higher priority against the pattern added to it first, this\r
+ will not necessarily be true when a multi-line match is in progress\r
+ because one of the complete multi-line patterns may not be completely\r
+ loaded in RegexWriter's buffer.  For this reason, the Transformer\r
+ class is equipped with a way to add a pattern and replacement rule\r
+ in three pieces -- a beginning (once this matches, nothing else in\r
+ the Transformer can match until the whole pattern matches), an\r
+ ending (the whole pattern is a String formed by adding the beginning\r
+ and ending), and a ReplaceRule.\r
+ <p>\r
+ An illustration of this is given in the this\r
+ <a href="../test/trans.java">example.</a>\r
+ */\r
+public class RegexWriter extends Writer {\r
+    Replacer repr;\r
+    Writer w;\r
+    WriterWrap ww;\r
+    StringBuffer sb = new StringBuffer();\r
+    PartialBuffer wrap = new PartialBuffer(sb);\r
+    int pos, epos;\r
+    int interval = 128;\r
+    int bufferSize = 2*1024;\r
+\r
+    public RegexWriter(Transformer t,Writer w) {\r
+       this.w = w;\r
+        ww = new WriterWrap(w);\r
+        repr = t.getReplacer();\r
+       repr.setBuffer(new StringBufferLike(ww));\r
+       repr.setSource(wrap);\r
+    }\r
+    public RegexWriter(Regex r,Writer w) {\r
+       this.w = w;\r
+        ww = new WriterWrap(w);\r
+        repr = r.getReplacer();\r
+       repr.setBuffer(new StringBufferLike(ww));\r
+       repr.setSource(wrap);\r
+    }\r
+\r
+    char EOLchar = '\n';\r
+    /** This method no longer serves any purpose.\r
+        @deprecated\r
+      */\r
+    public char getEOLchar() {\r
+        return EOLchar;\r
+    }\r
+    /** This method no longer serves any purpose.\r
+     @deprecated\r
+     */\r
+    public void setEOLchar(char c) {\r
+        EOLchar = c;\r
+    }\r
+\r
+    int max_lines=2;\r
+    /** This method no longer serves any purpose.\r
+     @deprecated\r
+     */\r
+    public int getMaxLines() { return max_lines; }\r
+    /** This method no longer serves any purpose.\r
+     @deprecated\r
+     */\r
+    public void setMaxLines(int ml) { max_lines = ml; }\r
+\r
+    void write() throws IOException {\r
+      Regex rex = repr.getRegex();\r
+      int eposOld = epos;\r
+      if(rex.matchAt(wrap,epos) && !wrap.overRun) {\r
+        while(pos < epos)\r
+          w.write(sb.charAt(pos++));\r
+        int to = rex.matchedTo();\r
+       repr.setPos(to);\r
+       repr.apply(rex,rex.getReplaceRule());\r
+       epos = pos = to;\r
+       if(epos == eposOld && epos < sb.length())\r
+         epos++;\r
+      } else if(!wrap.overRun && epos < sb.length()) {\r
+        epos++;\r
+      }\r
+      while(pos < epos)\r
+        w.write(sb.charAt(pos++));\r
+      if(epos == sb.length()) {\r
+       sb.setLength(1);\r
+       pos = epos = 1;\r
+      } else if(pos > bufferSize) {\r
+        for(int i=bufferSize;i<sb.length();i++)\r
+         sb.setCharAt(i-bufferSize,sb.charAt(i));\r
+        pos -= bufferSize;\r
+       epos -= bufferSize;\r
+       sb.setLength(sb.length()-bufferSize);\r
+      }\r
+    }\r
+\r
+    public void write(char[] ca,int b,int n) throws IOException {\r
+      int m = b+n;\r
+      for(int i=b;i<m;i++) {\r
+        sb.append(ca[i]);\r
+       if(sb.length() % interval == interval - 1) {\r
+         wrap.overRun = false;\r
+          while(epos+interval < sb.length() && !wrap.overRun) {\r
+            write();\r
+         }\r
+        }\r
+      }\r
+    }\r
+\r
+    public void flush() throws IOException {\r
+    }\r
+\r
+    public void close() throws IOException {\r
+       wrap.allowOverRun = false;\r
+       wrap.overRun = false;\r
+       while(epos < sb.length())\r
+         write();\r
+       write();\r
+       w.close();\r
+    }\r
+\r
+    /** The current size of the StringBuffer in use by RegexWriter. */\r
+    public int length() { return sb.length(); }\r
+\r
+    /** The character at location i in the StringBuffer. */\r
+    public char charAt(int i) { return sb.charAt(i); }\r
+\r
+    /** Set the interval at which regex patterns are checked. */\r
+    public void setInterval(int i) {\r
+      interval = i;\r
+    }\r
+\r
+    /** Get the interval at which regex matches are checked. */\r
+    public int getInterval() {\r
+      return interval;\r
+    }\r
+\r
+    /** Get the buffer size. */\r
+    public int getBufferSize() {\r
+      return bufferSize;\r
+    }\r
+\r
+    /** Set the buffer size. */\r
+    public void setBufferSize(int i) {\r
+      bufferSize = i;\r
+    }\r
+\r
+  static void test(String re,String inp,int n) throws Exception {\r
+    StringWriter sw = new StringWriter();\r
+    Regex rex = Regex.perlCode(re);\r
+    String res1 = rex.replaceAll(inp);\r
+    RegexWriter rw = new RegexWriter(rex,sw);\r
+    for(int i=0;i<inp.length();i++)\r
+      rw.write(inp.charAt(i));\r
+    rw.close();\r
+    String res2 = sw.toString();\r
+    if(!res1.equals(res2)) {\r
+      System.out.println("nmax="+n);\r
+      System.out.println("re="+re);\r
+      System.out.println("inp="+inp);\r
+      System.out.println("res1="+res1);\r
+      System.out.println("res2="+res2);\r
+      System.exit(255);\r
+    }\r
+  }\r
+  public static void main(String[] args) throws Exception {\r
+    for(int n=1;n<=1;n++) {\r
+      test("s/x/y/","-----x123456789",n);\r
+      test("s/x/y/","x123456789",n);\r
+      test("s/x/y/","-----x",n);\r
+      test("s/x.*?x/y/",".xx..x..x...x...x....x....x",n);\r
+      test("s/x.*x/[$&]/","--x........x--xx",n);\r
+      test("s/x.*x/[$&]/","--x........x------",n);\r
+      test("s/.$/a/m","bb\nbbb\nbbbb\nbbbbb\nbbbbbb\nbbbbbbbbbbbb",n);\r
+      test("s/.$/a/","123",n);\r
+      test("s/.$/a/","bb\nbbb\nbbbb\nbbbbb\nbbbbbb\nbb",n);\r
+      test("s/^./a/","bb\nbbb\nbbbb\nbbbbb\nbbbbbb\nbb",n);\r
+      test("s/$/a/","bbb",n);\r
+      test("s/^/a/","bbb",n);\r
+      test("s/^/a/","",n);\r
+      test("s{.*}{N}","xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",n);\r
+      test("s/.{0,7}/y/","AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",n);\r
+      test("s/x/$&/","xxx",n);\r
+    }\r
+    System.out.println("Success!!!");\r
+  }\r
+}\r