X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fcom%2Fstevesoft%2Fpat%2FReplaceRule.java;h=74a7a258cbf3cc8275ace069617321b3b599e179;hb=d7b76647ea9f7bd2d54fddf686d120b2c1f43506;hp=d4f09bbf3510befdb85f23d79f357de7e84b2a6a;hpb=7bc226b58110fa26d9dbd3f0c78095d06909ffc3;p=jalview.git
diff --git a/src/com/stevesoft/pat/ReplaceRule.java b/src/com/stevesoft/pat/ReplaceRule.java
index d4f09bb..74a7a25 100755
--- a/src/com/stevesoft/pat/ReplaceRule.java
+++ b/src/com/stevesoft/pat/ReplaceRule.java
@@ -1,398 +1,400 @@
-//
-// This software is now distributed according to
-// the Lesser Gnu Public License. Please see
-// http://www.gnu.org/copyleft/lesser.txt for
-// the details.
-// -- Happy Computing!
-//
-package com.stevesoft.pat;
-
-import java.util.*;
-
-/** ReplaceRule is a singly linked list of Objects which describe how
- to replace the matched portion of a String. The only member method
- that you absolutely need to define to use this class is apply(StringBuffer,RegRes) --
- although you may want define toString1() and clone1() (if you are
- unhappy with the default methods) that are needed by
- the clone() or toString() methods on this class.
- During the replacement process, each ReplaceRule tells the replacer
- what to add to StringBuffer and uses the contents of the Regular
- expression result to get the information it needs to
- do this. Here is an example
-
- @see com.stevesoft.pat.NullRule
- @see com.stevesoft.pat.AmpersandRule
- @see com.stevesoft.pat.BackRefRule
- @see com.stevesoft.pat.LeftRule
- @see com.stevesoft.pat.RightRule
- @see com.stevesoft.pat.StringRule
- */
-public abstract class ReplaceRule
-{
- /** points to the next ReplaceRule in the linked list. */
- protected ReplaceRule next = null;
- /** This function appends to the StringBufferLike the text you want
- to replaced the portion of the String last matched. */
- public abstract void apply(StringBufferLike sb, RegRes r);
-
- /** A rule describing how to clone only the current ReplaceRule,
- and none of the others in this linked list. It is called by
- clone() for each item in the list. */
- public Object clone1()
- {
- return new RuleHolder(this);
- }
-
- public final Object clone()
- {
- ReplaceRule x = (ReplaceRule) clone1();
- ReplaceRule xsav = x;
- ReplaceRule y = this;
- while (y.next != null)
- {
- x.next = (ReplaceRule) y.next.clone1();
- x.name = y.name;
- x = x.next;
- y = y.next;
- }
- return xsav;
- }
-
- static ReplaceRule add(ReplaceRule head, ReplaceRule adding)
- {
- if (head == null)
- {
- return head = adding;
- }
- head.addRule(adding);
- return head;
- }
-
- public ReplaceRule add(ReplaceRule adding)
- {
- return add(this, adding);
- }
-
- /** Add another ReplaceRule to the linked list. */
- public void addRule(ReplaceRule r)
- {
- if (next == null)
- {
- next = r;
- }
- else
- {
- next.addRule(r);
- }
- }
-
- static Regex getvar = null;
- final static Regex getv()
- {
- // Thanks to Michael Jimenez for pointing out the need
- // to clone getvar rather than simply returning it.
- // Previously this was not thread safe.
- //if(getvar != null) return getvar;
- if (getvar != null)
- {
- return (Regex) getvar.clone();
- }
- getvar =
- new Regex(
- "(?:\\\\(\\d+)|" + // ref 1
- "\\$(?:" +
- "(\\d+)|" + // ref 2
- "(\\w+)|" + // ref 3
- "([&'`])|" + // ref 4
- "\\{(?:(\\d+)|" + // ref 5
- "([^\n}\\\\]+))}" + // ref 6
- ")|" +
- "\\\\([nrbtaef])|" + // ref 7
- "\\\\c([\u0000-\uFFFF])|" + // ref 8
- "\\\\x([A-Fa-f0-9]{2})|" + // ref 9
- "\\\\([\u0000-\uFFFF])" + // ref 10
- ")");
- getvar.optimize();
- return getvar;
- }
-
- /** Compile a ReplaceRule using the text that would go between
- the second and third /'s in a typical substitution pattern
- in Perl: s/ ... / The argument to ReplaceRule.perlCode /.
- */
- public static ReplaceRule perlCode(String s)
- {
- //String sav_backGs = Regex.backGs;
- //int sav_backGto = Regex.backGto;
- try
- {
- int mf = 0, mt = 0;
- Regex gv = getv();
- ReplaceRule head = null;
- Object tmp = null;
- while (gv.searchFrom(s, mt))
- {
- int off = Regex.BackRefOffset - 1;
- mf = gv.matchedFrom();
- if (mf > mt)
- {
- head = add(head,
- new StringRule(s.substring(mt, mf)));
- }
- String var = null;
- if ( (var = gv.stringMatched(1 + off)) != null
- || (var = gv.stringMatched(2 + off)) != null
- || (var = gv.stringMatched(5 + off)) != null)
- {
- int d = 0;
- for (int i = 0; i < var.length(); i++)
- {
- d = 8 * d + (var.charAt(i) - '0');
- }
- if (var.length() == 1)
- {
- head = add(head, new BackRefRule(d));
- }
- else
- {
- head = new StringRule("" + (char) d);
- }
- }
- else if (
- (var = gv.stringMatched(10 + off)) != null)
- {
- if ("QELlUu".indexOf(var) >= 0)
- {
- head = add(head, new CodeRule(var.charAt(0)));
- }
- else
- {
- head = add(head, new StringRule(var));
- }
- }
- else if (
- (var = gv.stringMatched(3 + off)) != null
- || (var = gv.stringMatched(4 + off)) != null
- || (var = gv.stringMatched(6 + off)) != null)
- {
- String arg = "";
- int pc;
- if ( (pc = var.indexOf(':')) > 0)
- {
- arg = var.substring(pc + 1);
- var = var.substring(0, pc);
- }
- if (var.equals("&") || var.equals("MATCH"))
- {
- head = add(head, new AmpersandRule());
- }
- else if (var.equals("`") || var.equals("PREMATCH"))
- {
- head = add(head, new LeftRule());
- }
- else if (var.equals("'") || var.equals("POSTMATCH"))
- {
- head = add(head, new RightRule());
- }
- else if (var.equals("WANT_MORE_TEXT"))
- {
- head = add(head, new WantMoreTextReplaceRule());
- }
- else if (var.equals("POP"))
- {
- head = add(head, new PopRule());
- }
- else if (var.startsWith("+") && (tmp = defs.get(var.substring(1))) != null)
- {
- if (tmp instanceof Regex)
- {
- head = add(head, new PushRule(var.substring(1), (Regex) tmp));
- }
- else if (tmp instanceof Transformer)
- {
- head = add(head, new PushRule(var.substring(1), (Transformer) tmp));
- }
- else
- {
- head = add(head, new StringRule("${" + var + "}"));
- }
- }
- else if (var.startsWith("=") && (tmp = defs.get(var.substring(1))) != null)
- {
- if (tmp instanceof Regex)
- {
- head = add(head, new ChangeRule(var.substring(1), (Regex) tmp));
- }
- else if (tmp instanceof Transformer)
- {
- head = add(head,
- new ChangeRule(var.substring(1), (Transformer) tmp));
- }
- else
- {
- head = add(head, new StringRule("${" + var + "}"));
- }
- }
- else if ( (tmp = defs.get(var)) != null)
- {
- if (tmp instanceof ReplaceRule)
- {
- ReplaceRule alt = ( (ReplaceRule) tmp).arg(arg);
- if (alt == null)
- {
- alt = ( (ReplaceRule) tmp);
- }
- head = add(head, (ReplaceRule) (alt.clone()));
- }
- }
- else // can't figure out how to transform this thing...
- {
- head = add(head, new StringRule("${" + var + "}"));
- }
- }
- else if (
- (var = gv.stringMatched(7 + off)) != null)
- {
- char c = var.charAt(0);
- if (c == 'n')
- {
- head = add(head, new StringRule("\n"));
- }
- else if (c == 't')
- {
- head = add(head, new StringRule("\t"));
- }
- else if (c == 'r')
- {
- head = add(head, new StringRule("\r"));
- }
- else if (c == 'b')
- {
- head = add(head, new StringRule("\r"));
- }
- else if (c == 'a')
- {
- head = add(head, new StringRule("" + (char) 7));
- }
- else if (c == 'e')
- {
- head = add(head, new StringRule("" + (char) 27));
- }
- else if (c == 'f')
- {
- head = add(head, new StringRule("" + (char) 12));
- }
- }
- else if (
- (var = gv.stringMatched(8 + off)) != null)
- {
- char c = var.charAt(0);
- if (c < Ctrl.cmap.length)
- {
- c = Ctrl.cmap[c];
- }
- head = add(head, new StringRule("" + c));
- }
- else if (
- (var = gv.stringMatched(9 + off)) != null)
- {
- int d =
- 16 * getHexDigit(var.charAt(0)) +
- getHexDigit(var.charAt(1));
- head = add(head, new StringRule("" + (char) d));
- }
- mt = gv.matchedTo();
- }
- if (mt <= s.length())
- {
- head = add(head, new StringRule(s.substring(mt)));
- }
- return head;
- }
- finally
- {
- //Regex.backGs = sav_backGs;
- //Regex.backGto = sav_backGto;
- }
- }
-
- static Hashtable defs = new Hashtable();
- public static boolean isDefined(String s)
- {
- return defs.get(s) != null;
- }
-
- public static void define(String s, Regex r)
- {
- defs.put(s, r);
- }
-
- public static void define(String s, ReplaceRule r)
- {
- defs.put(s, r);
- r.name = s;
- }
-
- String name = getClass().getName();
-
- public static void define(String s, Transformer t)
- {
- defs.put(s, t);
- }
-
- public static void undefine(String s)
- {
- defs.remove(s);
- }
-
- /** This tells how to convert just the current element (and none
- of the other items in the linked list) to a String. This
- method is called by toString() for each item in the linked
- list. */
- public String toString1()
- {
- return "${" + name + "}";
- }
-
- /** Convert to a String. */
- public final String toString()
- {
- StringBuffer sb = new StringBuffer();
- sb.append(toString1());
- ReplaceRule rr = this.next;
- while (rr != null)
- {
- sb.append(rr.toString1());
- rr = rr.next;
- }
- return sb.toString();
- }
-
- /** Modified the behavior of a ReplaceRule by supplying
- an argument. If a ReplaceRule named "foo" is defined
- and the pattern "s/x/${foo:5}/" is given to Regex.perlCode,
- then the "foo" the definition of "foo" will be retrieved
- and arg("5") will be called. If the result is non-null,
- that is the ReplaceRule that will be used. If the result
- is null, then the pattern works just as if it were
- "s/x/${foo}/".
- @see com.stevesoft.pat.Validator#arg(java.lang.String)
- */
- public ReplaceRule arg(String s)
- {
- return null;
- }
-
- static int getHexDigit(char c)
- {
- if (c >= '0' && c <= '9')
- {
- return c - '0';
- }
- if (c >= 'a' && c <= 'f')
- {
- return c - 'a' + 10;
- }
- return c - 'A' + 10;
- }
-}
+//
+// This software is now distributed according to
+// the Lesser Gnu Public License. Please see
+// http://www.gnu.org/copyleft/lesser.txt for
+// the details.
+// -- Happy Computing!
+//
+package com.stevesoft.pat;
+
+import java.util.Hashtable;
+
+/**
+ * ReplaceRule is a singly linked list of Objects which describe how to replace
+ * the matched portion of a String. The only member method that you absolutely
+ * need to define to use this class is apply(StringBuffer,RegRes) -- although
+ * you may want define toString1() and clone1() (if you are unhappy with the
+ * default methods) that are needed by the clone() or toString() methods on this
+ * class. During the replacement process, each ReplaceRule tells the replacer
+ * what to add to StringBuffer and uses the contents of the Regular expression
+ * result to get the information it needs to do this. Here is an example
+ *
+ * @see com.stevesoft.pat.NullRule
+ * @see com.stevesoft.pat.AmpersandRule
+ * @see com.stevesoft.pat.BackRefRule
+ * @see com.stevesoft.pat.LeftRule
+ * @see com.stevesoft.pat.RightRule
+ * @see com.stevesoft.pat.StringRule
+ */
+public abstract class ReplaceRule
+{
+ /** points to the next ReplaceRule in the linked list. */
+ protected ReplaceRule next = null;
+
+ /**
+ * This function appends to the StringBufferLike the text you want to replaced
+ * the portion of the String last matched.
+ */
+ public abstract void apply(StringBufferLike sb, RegRes r);
+
+ /**
+ * A rule describing how to clone only the current ReplaceRule, and none of
+ * the others in this linked list. It is called by clone() for each item in
+ * the list.
+ */
+ public Object clone1()
+ {
+ return new RuleHolder(this);
+ }
+
+ public final Object clone()
+ {
+ ReplaceRule x = (ReplaceRule) clone1();
+ ReplaceRule xsav = x;
+ ReplaceRule y = this;
+ while (y.next != null)
+ {
+ x.next = (ReplaceRule) y.next.clone1();
+ x.name = y.name;
+ x = x.next;
+ y = y.next;
+ }
+ return xsav;
+ }
+
+ static ReplaceRule add(ReplaceRule head, ReplaceRule adding)
+ {
+ if (head == null)
+ {
+ return head = adding;
+ }
+ head.addRule(adding);
+ return head;
+ }
+
+ public ReplaceRule add(ReplaceRule adding)
+ {
+ return add(this, adding);
+ }
+
+ /** Add another ReplaceRule to the linked list. */
+ public void addRule(ReplaceRule r)
+ {
+ if (next == null)
+ {
+ next = r;
+ }
+ else
+ {
+ next.addRule(r);
+ }
+ }
+
+ static Regex getvar = null;
+
+ final static Regex getv()
+ {
+ // Thanks to Michael Jimenez for pointing out the need
+ // to clone getvar rather than simply returning it.
+ // Previously this was not thread safe.
+ // if(getvar != null) return getvar;
+ if (getvar != null)
+ {
+ return (Regex) getvar.clone();
+ }
+ getvar = new Regex("(?:\\\\(\\d+)|" + // ref 1
+ "\\$(?:" + "(\\d+)|" + // ref 2
+ "(\\w+)|" + // ref 3
+ "([&'`])|" + // ref 4
+ "\\{(?:(\\d+)|" + // ref 5
+ "([^\n}\\\\]+))}" + // ref 6
+ ")|" + "\\\\([nrbtaef])|" + // ref 7
+ "\\\\c([\u0000-\uFFFF])|" + // ref 8
+ "\\\\x([A-Fa-f0-9]{2})|" + // ref 9
+ "\\\\([\u0000-\uFFFF])" + // ref 10
+ ")");
+ getvar.optimize();
+ return getvar;
+ }
+
+ /**
+ * Compile a ReplaceRule using the text that would go between the second and
+ * third /'s in a typical substitution pattern in Perl: s/ ... / The
+ * argument to ReplaceRule.perlCode /.
+ */
+ public static ReplaceRule perlCode(String s)
+ {
+ // String sav_backGs = Regex.backGs;
+ // int sav_backGto = Regex.backGto;
+ try
+ {
+ int mf = 0, mt = 0;
+ Regex gv = getv();
+ ReplaceRule head = null;
+ Object tmp = null;
+ while (gv.searchFrom(s, mt))
+ {
+ int off = Regex.BackRefOffset - 1;
+ mf = gv.matchedFrom();
+ if (mf > mt)
+ {
+ head = add(head, new StringRule(s.substring(mt, mf)));
+ }
+ String var = null;
+ if ((var = gv.stringMatched(1 + off)) != null
+ || (var = gv.stringMatched(2 + off)) != null
+ || (var = gv.stringMatched(5 + off)) != null)
+ {
+ int d = 0;
+ for (int i = 0; i < var.length(); i++)
+ {
+ d = 8 * d + (var.charAt(i) - '0');
+ }
+ if (var.length() == 1)
+ {
+ head = add(head, new BackRefRule(d));
+ }
+ else
+ {
+ head = new StringRule("" + (char) d);
+ }
+ }
+ else if ((var = gv.stringMatched(10 + off)) != null)
+ {
+ if ("QELlUu".indexOf(var) >= 0)
+ {
+ head = add(head, new CodeRule(var.charAt(0)));
+ }
+ else
+ {
+ head = add(head, new StringRule(var));
+ }
+ }
+ else if ((var = gv.stringMatched(3 + off)) != null
+ || (var = gv.stringMatched(4 + off)) != null
+ || (var = gv.stringMatched(6 + off)) != null)
+ {
+ String arg = "";
+ int pc;
+ if ((pc = var.indexOf(':')) > 0)
+ {
+ arg = var.substring(pc + 1);
+ var = var.substring(0, pc);
+ }
+ if (var.equals("&") || var.equals("MATCH"))
+ {
+ head = add(head, new AmpersandRule());
+ }
+ else if (var.equals("`") || var.equals("PREMATCH"))
+ {
+ head = add(head, new LeftRule());
+ }
+ else if (var.equals("'") || var.equals("POSTMATCH"))
+ {
+ head = add(head, new RightRule());
+ }
+ else if (var.equals("WANT_MORE_TEXT"))
+ {
+ head = add(head, new WantMoreTextReplaceRule());
+ }
+ else if (var.equals("POP"))
+ {
+ head = add(head, new PopRule());
+ }
+ else if (var.startsWith("+")
+ && (tmp = defs.get(var.substring(1))) != null)
+ {
+ if (tmp instanceof Regex)
+ {
+ head = add(head, new PushRule(var.substring(1), (Regex) tmp));
+ }
+ else if (tmp instanceof Transformer)
+ {
+ head = add(head, new PushRule(var.substring(1),
+ (Transformer) tmp));
+ }
+ else
+ {
+ head = add(head, new StringRule("${" + var + "}"));
+ }
+ }
+ else if (var.startsWith("=")
+ && (tmp = defs.get(var.substring(1))) != null)
+ {
+ if (tmp instanceof Regex)
+ {
+ head = add(head,
+ new ChangeRule(var.substring(1), (Regex) tmp));
+ }
+ else if (tmp instanceof Transformer)
+ {
+ head = add(head, new ChangeRule(var.substring(1),
+ (Transformer) tmp));
+ }
+ else
+ {
+ head = add(head, new StringRule("${" + var + "}"));
+ }
+ }
+ else if ((tmp = defs.get(var)) != null)
+ {
+ if (tmp instanceof ReplaceRule)
+ {
+ ReplaceRule alt = ((ReplaceRule) tmp).arg(arg);
+ if (alt == null)
+ {
+ alt = ((ReplaceRule) tmp);
+ }
+ head = add(head, (ReplaceRule) (alt.clone()));
+ }
+ }
+ else
+ // can't figure out how to transform this thing...
+ {
+ head = add(head, new StringRule("${" + var + "}"));
+ }
+ }
+ else if ((var = gv.stringMatched(7 + off)) != null)
+ {
+ char c = var.charAt(0);
+ if (c == 'n')
+ {
+ head = add(head, new StringRule("\n"));
+ }
+ else if (c == 't')
+ {
+ head = add(head, new StringRule("\t"));
+ }
+ else if (c == 'r')
+ {
+ head = add(head, new StringRule("\r"));
+ }
+ else if (c == 'b')
+ {
+ head = add(head, new StringRule("\r"));
+ }
+ else if (c == 'a')
+ {
+ head = add(head, new StringRule("" + (char) 7));
+ }
+ else if (c == 'e')
+ {
+ head = add(head, new StringRule("" + (char) 27));
+ }
+ else if (c == 'f')
+ {
+ head = add(head, new StringRule("" + (char) 12));
+ }
+ }
+ else if ((var = gv.stringMatched(8 + off)) != null)
+ {
+ char c = var.charAt(0);
+ if (c < Ctrl.cmap.length)
+ {
+ c = Ctrl.cmap[c];
+ }
+ head = add(head, new StringRule("" + c));
+ }
+ else if ((var = gv.stringMatched(9 + off)) != null)
+ {
+ int d = 16 * getHexDigit(var.charAt(0))
+ + getHexDigit(var.charAt(1));
+ head = add(head, new StringRule("" + (char) d));
+ }
+ mt = gv.matchedTo();
+ }
+ if (mt <= s.length())
+ {
+ head = add(head, new StringRule(s.substring(mt)));
+ }
+ return head;
+ } finally
+ {
+ // Regex.backGs = sav_backGs;
+ // Regex.backGto = sav_backGto;
+ }
+ }
+
+ static Hashtable defs = new Hashtable();
+
+ public static boolean isDefined(String s)
+ {
+ return defs.get(s) != null;
+ }
+
+ public static void define(String s, Regex r)
+ {
+ defs.put(s, r);
+ }
+
+ public static void define(String s, ReplaceRule r)
+ {
+ defs.put(s, r);
+ r.name = s;
+ }
+
+ String name = getClass().getName();
+
+ public static void define(String s, Transformer t)
+ {
+ defs.put(s, t);
+ }
+
+ public static void undefine(String s)
+ {
+ defs.remove(s);
+ }
+
+ /**
+ * This tells how to convert just the current element (and none of the other
+ * items in the linked list) to a String. This method is called by toString()
+ * for each item in the linked list.
+ */
+ public String toString1()
+ {
+ return "${" + name + "}";
+ }
+
+ /** Convert to a String. */
+ public final String toString()
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append(toString1());
+ ReplaceRule rr = this.next;
+ while (rr != null)
+ {
+ sb.append(rr.toString1());
+ rr = rr.next;
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Modified the behavior of a ReplaceRule by supplying an argument. If a
+ * ReplaceRule named "foo" is defined and the pattern "s/x/${foo:5}/" is given
+ * to Regex.perlCode, then the "foo" the definition of "foo" will be retrieved
+ * and arg("5") will be called. If the result is non-null, that is the
+ * ReplaceRule that will be used. If the result is null, then the pattern
+ * works just as if it were "s/x/${foo}/".
+ *
+ * @see com.stevesoft.pat.Validator#arg(java.lang.String)
+ */
+ public ReplaceRule arg(String s)
+ {
+ return null;
+ }
+
+ static int getHexDigit(char c)
+ {
+ if (c >= '0' && c <= '9')
+ {
+ return c - '0';
+ }
+ if (c >= 'a' && c <= 'f')
+ {
+ return c - 'a' + 10;
+ }
+ return c - 'A' + 10;
+ }
+}