Formatting
[jalview.git] / src / com / stevesoft / pat / Pattern.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.util.*;\r
11 \r
12 /**\r
13         Shareware: package pat\r
14    <a href="copyright.html">Copyright 2001, Steven R. Brandt</a>\r
15  */\r
16 /**\r
17  Class Pattern is the base class on which all the other pattern\r
18  elements are built. */\r
19 \r
20 public abstract class Pattern\r
21 {\r
22   /** The ESC character, the user can provide his own value\r
23           for the escape character through regex.esc */\r
24   public final static char ESC = '\\';\r
25   final static String PROTECT_THESE = "[]{}(),$,-\"^.";\r
26 \r
27   /** The interal match function, it must be provided by any\r
28       class which wishes to extend Pattern. */\r
29   public abstract int matchInternal(int i, Pthings p);\r
30 \r
31   public abstract String toString();\r
32 \r
33   // Class Pattern is a singly linked list\r
34   // chained together by member next.  The member\r
35   // parent is used so that sub patterns can access\r
36   // the chain they are branching from.\r
37   Pattern next = null, parent = null;\r
38 \r
39   /** This gets the next element of a Pattern that\r
40           we wish to match.  If we are at the end of a\r
41           subchain of patterns, it will return us to the\r
42           parent chain. */\r
43   public Pattern getNext()\r
44   {\r
45     return next != null ? next :\r
46         (parent == null ? null : parent.getNext());\r
47   }\r
48 \r
49   /** Call this method if you have a pattern element that\r
50           takes a sub pattern (such as Or), and\r
51           after you have added a sub pattern to the current\r
52           pattern element. */\r
53   public void setParent(Pattern p)\r
54   {\r
55     if (next != null)\r
56     {\r
57       next.setParent(p);\r
58     }\r
59     else\r
60     {\r
61       parent = p;\r
62     }\r
63   }\r
64 \r
65   /** This determines if the remainder of a Pattern\r
66           matches.  Type "return nextMatch" from within\r
67           matchInternal if the current\r
68           Pattern matches.  Otherwise, return a -1.*/\r
69   public int nextMatch(int i, Pthings pt)\r
70   {\r
71     Pattern p = getNext();\r
72     /*if(p == null) return i;\r
73             return p.matchInternal(i,pt);*/\r
74     return p == null ? i : p.matchInternal(i, pt);\r
75   }\r
76 \r
77   /** This is a toString() for the remainder\r
78           of the Pattern elements after this one.\r
79           use this when overriding toString(). Called from\r
80           within toString(). */\r
81   public String nextString()\r
82   {\r
83     if (next == null)\r
84     {\r
85       return "";\r
86     }\r
87     return next.toString();\r
88   }\r
89 \r
90   /** a method to detect whether char c is in String s */\r
91   final static boolean inString(char c, String s)\r
92   {\r
93     int i;\r
94     for (i = 0; i < s.length(); i++)\r
95     {\r
96       if (s.charAt(i) == c)\r
97       {\r
98         return true;\r
99       }\r
100     }\r
101     return false;\r
102   }\r
103 \r
104   /** A method to create a string that protects the characters\r
105           listed in PROTECT_THESE by prepending the esc character.\r
106           The esc character itself is automatically protected. */\r
107   final static\r
108       String protect(String s, String PROTECT_THESE, char esc)\r
109   {\r
110     int i;\r
111     StringBuffer sb = new StringBuffer();\r
112     String p = PROTECT_THESE + esc;\r
113     for (i = 0; i < s.length(); i++)\r
114     {\r
115       char c = s.charAt(i);\r
116       if (inString(c, p))\r
117       {\r
118         sb.append(esc);\r
119       }\r
120       sb.append(c);\r
121     }\r
122     return sb.toString();\r
123   }\r
124 \r
125   /** This can be used to perform a match test from\r
126           within class Pattern. */\r
127   public int match(StringLike s, Pthings pt)\r
128   {\r
129     return matchAt(s, 0, pt);\r
130   }\r
131 \r
132   /** This can be used to perform a match test from\r
133           within class Pattern. */\r
134   public int matchAt(StringLike s, int i, Pthings pt)\r
135   {\r
136     pt.src = s;\r
137     int r = matchInternal(i, pt);\r
138     if (r < 0)\r
139     {\r
140       return -1;\r
141     }\r
142     mfrom = r < i ? r + 1 : i;\r
143     return r < i ? i - r - 1 : r - i;\r
144   }\r
145 \r
146   int mfrom = 0;\r
147 \r
148   // Detect masked characters\r
149   final boolean Masked(int i, Pthings pt)\r
150   {\r
151     return pt.cbits == null ? false : pt.cbits.get(i);\r
152   }\r
153 \r
154   /** add a Pattern to the singly-linked Pattern chain. */\r
155   public Pattern add(Pattern p)\r
156   {\r
157     if (next == null)\r
158     {\r
159       if (p == null)\r
160       {\r
161         return this;\r
162       }\r
163       next = p;\r
164       p.parent = parent;\r
165       parent = null;\r
166     }\r
167     else\r
168     {\r
169       next.add(p);\r
170     }\r
171     return this;\r
172   }\r
173 \r
174   /** The minimum number of characters which\r
175       this pattern element can match. */\r
176   public patInt minChars()\r
177   {\r
178     return new patInt(0);\r
179   }\r
180 \r
181   /** The maximum number of characters which\r
182       this pattern element can match. */\r
183   public patInt maxChars()\r
184   {\r
185     return new patInf();\r
186   }\r
187 \r
188   /** return minimum number of characters in pattern */\r
189   public final patInt countMinChars()\r
190   {\r
191     Pattern p = this;\r
192     patInt sum = new patInt(0);\r
193     while (p != null)\r
194     {\r
195       sum.pluseq(p.minChars());\r
196       p = p.next;\r
197     }\r
198     return sum;\r
199   }\r
200 \r
201   /** return maximum number of characters in pattern */\r
202   public final patInt countMaxChars()\r
203   {\r
204     Pattern p = this;\r
205     patInt sum = new patInt(0);\r
206     while (p != null)\r
207     {\r
208       sum.pluseq(p.maxChars());\r
209       p = p.next;\r
210     }\r
211     return sum;\r
212   }\r
213 \r
214   // This method is only needed by Multi_stage2 so far...\r
215   // the reason is that it may try something else after a\r
216   // match succeeds.  OrMark will only record the last thing\r
217   // tried in marks, so we need to backup the result of the\r
218   // last successful match and restore it if the next one\r
219   // does not succeed.\r
220   final int testMatch(Pattern p, int pos, Pthings pt)\r
221   {\r
222     int[] tab = null;\r
223     if (pt.marks != null)\r
224     {\r
225       try\r
226       {\r
227         tab = new int[pt.marks.length];\r
228         for (int i = 0; i < tab.length; i++)\r
229         {\r
230           tab[i] = pt.marks[i];\r
231         }\r
232       }\r
233       catch (Throwable t)\r
234       {}\r
235     }\r
236     int ret = p.matchInternal(pos, pt);\r
237     if (ret < 0)\r
238     {\r
239       pt.marks = tab;\r
240     }\r
241     return ret;\r
242   }\r
243 \r
244   /** Clones this pattern elements without cloning others in the\r
245       linked list. */\r
246   Pattern clone1(Hashtable h)\r
247   {\r
248     throw new Error("No such method as clone1 for " + getClass().getName());\r
249   }\r
250 \r
251   Pattern clone(Hashtable h)\r
252   {\r
253     Pattern p = (Pattern) h.get(this);\r
254     if (p != null)\r
255     {\r
256       return p;\r
257     }\r
258     p = clone1(h);\r
259     if (p == null)\r
260     {\r
261       throw new Error("Null from clone1!");\r
262     }\r
263     h.put(this, p);\r
264     h.put(p, p);\r
265     if (next != null)\r
266     {\r
267       p.next = next.clone(h);\r
268     }\r
269     if (parent != null)\r
270     {\r
271       p.parent = parent.clone(h);\r
272     }\r
273     return p;\r
274   }\r
275 \r
276   public boolean equals(Object o)\r
277   {\r
278     return o == this;\r
279   }\r
280 };\r