// // 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 jalview.util.MessageManager; import java.util.*; /** Shareware: package pat Copyright 2001, Steven R. Brandt */ /** * Class Pattern is the base class on which all the other pattern elements are * built. */ public abstract class Pattern { /** * The ESC character, the user can provide his own value for the escape * character through regex.esc */ public final static char ESC = '\\'; final static String PROTECT_THESE = "[]{}(),$,-\"^."; /** * The interal match function, it must be provided by any class which wishes * to extend Pattern. */ public abstract int matchInternal(int i, Pthings p); public abstract String toString(); // Class Pattern is a singly linked list // chained together by member next. The member // parent is used so that sub patterns can access // the chain they are branching from. Pattern next = null, parent = null; /** * This gets the next element of a Pattern that we wish to match. If we are at * the end of a subchain of patterns, it will return us to the parent chain. */ public Pattern getNext() { return next != null ? next : (parent == null ? null : parent.getNext()); } /** * Call this method if you have a pattern element that takes a sub pattern * (such as Or), and after you have added a sub pattern to the current pattern * element. */ public void setParent(Pattern p) { if (next != null) { next.setParent(p); } else { parent = p; } } /** * This determines if the remainder of a Pattern matches. Type "return * nextMatch" from within matchInternal if the current Pattern matches. * Otherwise, return a -1. */ public int nextMatch(int i, Pthings pt) { Pattern p = getNext(); /* * if(p == null) return i; return p.matchInternal(i,pt); */ return p == null ? i : p.matchInternal(i, pt); } /** * This is a toString() for the remainder of the Pattern elements after this * one. use this when overriding toString(). Called from within toString(). */ public String nextString() { if (next == null) { return ""; } return next.toString(); } /** a method to detect whether char c is in String s */ final static boolean inString(char c, String s) { int i; for (i = 0; i < s.length(); i++) { if (s.charAt(i) == c) { return true; } } return false; } /** * A method to create a string that protects the characters listed in * PROTECT_THESE by prepending the esc character. The esc character itself is * automatically protected. */ final static String protect(String s, String PROTECT_THESE, char esc) { int i; javajs.util.SB sb = new javajs.util.SB(); String p = PROTECT_THESE + esc; for (i = 0; i < s.length(); i++) { char c = s.charAt(i); if (inString(c, p)) { sb.appendC(esc); } sb.appendC(c); } return sb.toString(); } /** * This can be used to perform a match test from within class Pattern. */ public int match(StringLike s, Pthings pt) { return matchAt(s, 0, pt); } /** * This can be used to perform a match test from within class Pattern. */ public int matchAt(StringLike s, int i, Pthings pt) { pt.src = s; int r = matchInternal(i, pt); if (r < 0) { return -1; } mfrom = r < i ? r + 1 : i; return r < i ? i - r - 1 : r - i; } int mfrom = 0; // Detect masked characters final boolean Masked(int i, Pthings pt) { return pt.cbits == null ? false : pt.cbits.get(i); } /** add a Pattern to the singly-linked Pattern chain. */ public Pattern add(Pattern p) { if (next == null) { if (p == null) { return this; } next = p; p.parent = parent; parent = null; } else { next.add(p); } return this; } /** * The minimum number of characters which this pattern element can match. */ public patInt minChars() { return new patInt(0); } /** * The maximum number of characters which this pattern element can match. */ public patInt maxChars() { return new patInf(); } /** return minimum number of characters in pattern */ public final patInt countMinChars() { Pattern p = this; patInt sum = new patInt(0); while (p != null) { sum.pluseq(p.minChars()); p = p.next; } return sum; } /** return maximum number of characters in pattern */ public final patInt countMaxChars() { Pattern p = this; patInt sum = new patInt(0); while (p != null) { sum.pluseq(p.maxChars()); p = p.next; } return sum; } // This method is only needed by Multi_stage2 so far... // the reason is that it may try something else after a // match succeeds. OrMark will only record the last thing // tried in marks, so we need to backup the result of the // last successful match and restore it if the next one // does not succeed. final int testMatch(Pattern p, int pos, Pthings pt) { int[] tab = null; if (pt.marks != null) { try { tab = new int[pt.marks.length]; for (int i = 0; i < tab.length; i++) { tab[i] = pt.marks[i]; } } catch (Throwable t) { } } int ret = p.matchInternal(pos, pt); if (ret < 0) { pt.marks = tab; } return ret; } /** * Clones this pattern elements without cloning others in the linked list. */ Pattern clone1(Hashtable h) { throw new Error(MessageManager.formatMessage("error.no_such_method_as_clone1_for", new String[]{getClass().getName()})); } Pattern clone(Hashtable h) { Pattern p = (Pattern) h.get(this); if (p != null) { return p; } p = clone1(h); if (p == null) { throw new Error(MessageManager.getString("error.null_from_clone1")); } h.put(this, p); h.put(p, p); if (next != null) { p.next = next.clone(h); } if (parent != null) { p.parent = parent.clone(h); } return p; } public boolean equals(Object o) { return o == this; } };