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 */ matchInternal(int i, Pthings p)37 public abstract int matchInternal(int i, Pthings p); 38 toString()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 */ getNext()51 public Pattern getNext() 52 { 53 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 */ setParent(Pattern p)61 public void setParent(Pattern p) 62 { 63 if (next != null) 64 { 65 next.setParent(p); 66 } 67 else 68 { 69 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 */ nextMatch(int i, Pthings pt)78 public int nextMatch(int i, Pthings pt) 79 { 80 Pattern p = getNext(); 81 /* 82 * if(p == null) return i; return p.matchInternal(i,pt); 83 */ 84 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 */ nextString()91 public String nextString() 92 { 93 if (next == null) 94 { 95 return ""; 96 } 97 return next.toString(); 98 } 99 100 /** a method to detect whether char c is in String s */ inString(char c, String s)101 final static boolean inString(char c, String s) 102 { 103 int i; 104 for (i = 0; i < s.length(); i++) 105 { 106 if (s.charAt(i) == c) 107 { 108 return true; 109 } 110 } 111 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 */ protect(String s, String PROTECT_THESE, char esc)119 final static String protect(String s, String PROTECT_THESE, char esc) 120 { 121 int i; 122 StringBuffer sb = new StringBuffer(); 123 String p = PROTECT_THESE + esc; 124 for (i = 0; i < s.length(); i++) 125 { 126 char c = s.charAt(i); 127 if (inString(c, p)) 128 { 129 sb.append(esc); 130 } 131 sb.append(c); 132 } 133 return sb.toString(); 134 } 135 136 /** 137 * This can be used to perform a match test from within class Pattern. 138 */ match(StringLike s, Pthings pt)139 public int match(StringLike s, Pthings pt) 140 { 141 return matchAt(s, 0, pt); 142 } 143 144 /** 145 * This can be used to perform a match test from within class Pattern. 146 */ matchAt(StringLike s, int i, Pthings pt)147 public int matchAt(StringLike s, int i, Pthings pt) 148 { 149 pt.src = s; 150 int r = matchInternal(i, pt); 151 if (r < 0) 152 { 153 return -1; 154 } 155 mfrom = r < i ? r + 1 : i; 156 return r < i ? i - r - 1 : r - i; 157 } 158 159 int mfrom = 0; 160 161 // Detect masked characters 162 final boolean Masked(int i, Pthings pt) 163 { 164 return pt.cbits == null ? false : pt.cbits.get(i); 165 } 166 167 /** add a Pattern to the singly-linked Pattern chain. */ 168 public Pattern add(Pattern p) 169 { 170 if (next == null) 171 { 172 if (p == null) 173 { 174 return this; 175 } 176 next = p; 177 p.parent = parent; 178 parent = null; 179 } 180 else 181 { 182 next.add(p); 183 } 184 return this; 185 } 186 187 /** 188 * The minimum number of characters which this pattern element can match. 189 */ 190 public patInt minChars() 191 { 192 return new patInt(0); 193 } 194 195 /** 196 * The maximum number of characters which this pattern element can match. 197 */ 198 public patInt maxChars() 199 { 200 return new patInf(); 201 } 202 203 /** return minimum number of characters in pattern */ 204 public final patInt countMinChars() 205 { 206 Pattern p = this; 207 patInt sum = new patInt(0); 208 while (p != null) 209 { 210 sum.pluseq(p.minChars()); 211 p = p.next; 212 } 213 return sum; 214 } 215 216 /** return maximum number of characters in pattern */ 217 public final patInt countMaxChars() 218 { 219 Pattern p = this; 220 patInt sum = new patInt(0); 221 while (p != null) 222 { 223 sum.pluseq(p.maxChars()); 224 p = p.next; 225 } 226 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 final int testMatch(Pattern p, int pos, Pthings pt) 236 { 237 int[] tab = null; 238 if (pt.marks != null) 239 { 240 try 241 { 242 tab = new int[pt.marks.length]; 243 for (int i = 0; i < tab.length; i++) 244 { 245 tab[i] = pt.marks[i]; 246 } 247 } catch (Throwable t) 248 { 249 } 250 } 251 int ret = p.matchInternal(pos, pt); 252 if (ret < 0) 253 { 254 pt.marks = tab; 255 } 256 return ret; 257 } 258 259 /** 260 * Clones this pattern elements without cloning others in the linked list. 261 */ 262 Pattern clone1(Hashtable h) 263 { 264 throw new Error(MessageManager.formatMessage( 265 "error.no_such_method_as_clone1_for", new String[] { getClass() 266 .getName() })); 267 } 268 269 Pattern clone(Hashtable h) 270 { 271 Pattern p = (Pattern) h.get(this); 272 if (p != null) 273 { 274 return p; 275 } 276 p = clone1(h); 277 if (p == null) 278 { 279 throw new Error(MessageManager.getString("error.null_from_clone1")); 280 } 281 h.put(this, p); 282 h.put(p, p); 283 if (next != null) 284 { 285 p.next = next.clone(h); 286 } 287 if (parent != null) 288 { 289 p.parent = parent.clone(h); 290 } 291 return p; 292 } 293 294 public boolean equals(Object o) 295 { 296 return o == this; 297 } 298 }; 299