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