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
6 // -- Happy Computing!
\r
8 package com.stevesoft.pat;
\r
11 Shareware: package pat
\r
12 <a href="copyright.html">Copyright 2001, Steven R. Brandt</a>
\r
14 Class Pattern is the base class on which all the other pattern
\r
15 elements are built. */
\r
17 public abstract class Pattern {
\r
18 /** The ESC character, the user can provide his own value
\r
19 for the escape character through regex.esc */
\r
20 public final static char ESC = '\\';
\r
21 final static String PROTECT_THESE = "[]{}(),$,-\"^.";
\r
23 /** The interal match function, it must be provided by any
\r
24 class which wishes to extend Pattern. */
\r
25 public abstract int matchInternal(int i,Pthings p);
\r
26 public abstract String toString();
\r
28 // Class Pattern is a singly linked list
\r
29 // chained together by member next. The member
\r
30 // parent is used so that sub patterns can access
\r
31 // the chain they are branching from.
\r
32 Pattern next=null,parent=null;
\r
34 /** This gets the next element of a Pattern that
\r
35 we wish to match. If we are at the end of a
\r
36 subchain of patterns, it will return us to the
\r
38 public Pattern getNext() {
\r
39 return next != null ? next :
\r
40 (parent == null ? null : parent.getNext());
\r
42 /** Call this method if you have a pattern element that
\r
43 takes a sub pattern (such as Or), and
\r
44 after you have added a sub pattern to the current
\r
46 public void setParent(Pattern p) {
\r
47 if(next != null) next.setParent(p);
\r
50 /** This determines if the remainder of a Pattern
\r
51 matches. Type "return nextMatch" from within
\r
52 matchInternal if the current
\r
53 Pattern matches. Otherwise, return a -1.*/
\r
54 public int nextMatch(int i,Pthings pt) {
\r
55 Pattern p = getNext();
\r
56 /*if(p == null) return i;
\r
57 return p.matchInternal(i,pt);*/
\r
58 return p==null ? i : p.matchInternal(i,pt);
\r
60 /** This is a toString() for the remainder
\r
61 of the Pattern elements after this one.
\r
62 use this when overriding toString(). Called from
\r
63 within toString(). */
\r
64 public String nextString() {
\r
65 if(next == null) return "";
\r
66 return next.toString();
\r
69 /** a method to detect whether char c is in String s */
\r
70 final static boolean inString(char c,String s) {
\r
72 for(i=0;i<s.length();i++)
\r
78 /** A method to create a string that protects the characters
\r
79 listed in PROTECT_THESE by prepending the esc character.
\r
80 The esc character itself is automatically protected. */
\r
82 String protect(String s,String PROTECT_THESE,char esc) {
\r
84 StringBuffer sb = new StringBuffer();
\r
85 String p = PROTECT_THESE+esc;
\r
86 for(i=0;i<s.length();i++) {
\r
87 char c = s.charAt(i);
\r
92 return sb.toString();
\r
95 /** This can be used to perform a match test from
\r
96 within class Pattern. */
\r
97 public int match(StringLike s,Pthings pt) {
\r
98 return matchAt(s,0,pt);
\r
100 /** This can be used to perform a match test from
\r
101 within class Pattern. */
\r
102 public int matchAt(StringLike s,int i,Pthings pt) {
\r
104 int r = matchInternal(i,pt);
\r
105 if(r < 0) return -1;
\r
106 mfrom = r<i ? r+1 : i;
\r
107 return r<i ? i-r-1 : r-i;
\r
111 // Detect masked characters
\r
112 final boolean Masked(int i,Pthings pt) {
\r
113 return pt.cbits == null ? false : pt.cbits.get(i);
\r
116 /** add a Pattern to the singly-linked Pattern chain. */
\r
117 public Pattern add(Pattern p) {
\r
119 if(p==null) return this;
\r
123 } else next.add(p);
\r
126 /** The minimum number of characters which
\r
127 this pattern element can match. */
\r
128 public patInt minChars() { return new patInt(0); }
\r
129 /** The maximum number of characters which
\r
130 this pattern element can match. */
\r
131 public patInt maxChars() { return new patInf(); }
\r
132 /** return minimum number of characters in pattern */
\r
133 public final patInt countMinChars() {
\r
135 patInt sum = new patInt(0);
\r
137 sum.pluseq(p.minChars());
\r
142 /** return maximum number of characters in pattern */
\r
143 public final patInt countMaxChars() {
\r
145 patInt sum = new patInt(0);
\r
147 sum.pluseq(p.maxChars());
\r
153 // This method is only needed by Multi_stage2 so far...
\r
154 // the reason is that it may try something else after a
\r
155 // match succeeds. OrMark will only record the last thing
\r
156 // tried in marks, so we need to backup the result of the
\r
157 // last successful match and restore it if the next one
\r
158 // does not succeed.
\r
159 final int testMatch(Pattern p,int pos,Pthings pt) {
\r
161 if(pt.marks != null) try {
\r
162 tab = new int[pt.marks.length];
\r
163 for(int i=0;i<tab.length;i++)
\r
164 tab[i] = pt.marks[i];
\r
165 } catch(Throwable t) {}
\r
166 int ret = p.matchInternal(pos,pt);
\r
167 if(ret < 0) pt.marks = tab;
\r
171 /** Clones this pattern elements without cloning others in the
\r
173 Pattern clone1(Hashtable h) {
\r
174 throw new Error("No such method as clone1 for "+getClass().getName());
\r
176 Pattern clone(Hashtable h) {
\r
177 Pattern p = (Pattern)h.get(this);
\r
182 if(p==null)throw new Error("Null from clone1!");
\r
185 if(next != null) p.next = next.clone(h);
\r
186 if(parent != null) p.parent = parent.clone(h);
\r
189 public boolean equals(Object o) {
\r