/interpreter/tags/at2-build190607/src/edu/vub/util/Matcher.java
Java | 305 lines | 115 code | 27 blank | 163 comment | 15 complexity | 36dc0f3a9709835a3fb258fc5f2533e3 MD5 | raw file
1/* Matcher.java -- Instance of a regular expression applied to a char sequence. 2 Copyright (C) 2002, 2004 Free Software Foundation, Inc. 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 19 02111-1307 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38package edu.vub.util; 39 40import edu.vub.util.regexp.REMatch; 41 42/** 43 * Instance of a regular expression applied to a char sequence. 44 * 45 * @since 1.4 46 */ 47public class Matcher { 48 private Pattern pattern; 49 50 private StringBuffer input; 51 52 private int position; 53 54 private int appendPosition; 55 56 private REMatch match; 57 58 Matcher(Pattern pattern, StringBuffer input) { 59 this.pattern = pattern; 60 this.input = input; 61 } 62 63 /** 64 * @param sb The target string buffer 65 * @param replacement The replacement string 66 * 67 * @exception IllegalStateException If no match has yet been attempted, 68 * or if the previous match operation failed 69 * @exception IndexOutOfBoundsException If the replacement string refers 70 * to a capturing group that does not exist in the pattern 71 */ 72 public Matcher appendReplacement(StringBuffer sb, String replacement) 73 throws IllegalStateException { 74 assertMatchOp(); 75 sb.append(input.substring(appendPosition, match.getStartIndex()) 76 .toString()); 77 sb.append(match.substituteInto(replacement)); 78 appendPosition = match.getEndIndex(); 79 return this; 80 } 81 82 /** 83 * @param sb The target string buffer 84 */ 85 public StringBuffer appendTail(StringBuffer sb) { 86 sb.append(input.substring(appendPosition, input.length()).toString()); 87 return sb; 88 } 89 90 /** 91 * @exception IllegalStateException If no match has yet been attempted, 92 * or if the previous match operation failed 93 */ 94 public int end() throws IllegalStateException { 95 assertMatchOp(); 96 return match.getEndIndex(); 97 } 98 99 /** 100 * @param group The index of a capturing group in this matcher's pattern 101 * 102 * @exception IllegalStateException If no match has yet been attempted, 103 * or if the previous match operation failed 104 * @exception IndexOutOfBoundsException If the replacement string refers 105 * to a capturing group that does not exist in the pattern 106 */ 107 public int end(int group) throws IllegalStateException { 108 assertMatchOp(); 109 return match.getEndIndex(group); 110 } 111 112 /** 113 * Attempts to find the next subsequence of the input sequence that matches the pattern. 114 * <p> 115 * This method starts at the beginning of the input sequence or, if a previous invocation of 116 * the method was successful and the matcher has not since been reset, at the first character 117 * not matched by the previous match. 118 * <p> 119 * If the match succeeds then more information can be obtained via the start, end, and group 120 * methods. 121 * @return true if, and only if, a subsequence of the input sequence matches this matcher's pattern 122 */ 123 public boolean find() { 124 boolean first = (match == null); 125 match = pattern.getRE().getMatch(input, position); 126 if (match != null) { 127 int endIndex = match.getEndIndex(); 128 // Are we stuck at the same position? 129 if (!first && endIndex == position) { 130 match = null; 131 // Not at the end of the input yet? 132 if (position < input.length() - 1) { 133 position++; 134 return find(position); 135 } else 136 return false; 137 } 138 position = endIndex; 139 return true; 140 } 141 return false; 142 } 143 144 /** 145 * @param start The index to start the new pattern matching 146 * 147 * @exception IndexOutOfBoundsException If the replacement string refers 148 * to a capturing group that does not exist in the pattern 149 */ 150 public boolean find(int start) { 151 match = pattern.getRE().getMatch(input, start); 152 if (match != null) { 153 position = match.getEndIndex(); 154 return true; 155 } 156 return false; 157 } 158 159 /** 160 * @exception IllegalStateException If no match has yet been attempted, 161 * or if the previous match operation failed 162 */ 163 public String group() { 164 assertMatchOp(); 165 return match.toString(); 166 } 167 168 /** 169 * @param group The index of a capturing group in this matcher's pattern 170 * 171 * @exception IllegalStateException If no match has yet been attempted, 172 * or if the previous match operation failed 173 * @exception IndexOutOfBoundsException If the replacement string refers 174 * to a capturing group that does not exist in the pattern 175 */ 176 public String group(int group) throws IllegalStateException { 177 assertMatchOp(); 178 return match.toString(group); 179 } 180 181 /** 182 * @param replacement The replacement string 183 */ 184 public String replaceFirst(String replacement) { 185 reset(); 186 // Semantics might not quite match 187 return pattern.getRE().substitute(input, replacement, position); 188 } 189 190 /** 191 * @param replacement The replacement string 192 */ 193 public String replaceAll(String replacement) { 194 reset(); 195 return pattern.getRE().substituteAll(input, replacement, position); 196 } 197 198 /** 199 * Returns the number of capturing groups in this matcher's pattern. 200 * <p> 201 * Group zero denotes the entire pattern by convention. It is not included in this count. 202 * <p> 203 * Any non-negative integer smaller than or equal to the value returned by this method is 204 * guaranteed to be a valid group index for this matcher. 205 * 206 * @return The number of capturing groups in this matcher's pattern 207 */ 208 public int groupCount() { 209 return pattern.getRE().getNumSubs(); 210 } 211 212 /** 213 * Attempts to match the input sequence, starting at the beginning, against the pattern. 214 * <p> 215 * Like the <code>matches</code> method, this method always starts at the beginning of the 216 * input sequence; unlike that method, it does not require that the entire input sequence be 217 * matched. 218 * <p> 219 * If the match succeeds then more information can be obtained via the <code>start</code>, 220 * <code>end</code>, and <code>group</code> methods. 221 * 222 * @return true if, and only if, a prefix of the input sequence matches this matcher's pattern 223 */ 224 public boolean lookingAt() { 225 match = pattern.getRE().getMatch(input, 0); 226 if (match != null) { 227 if (match.getStartIndex() == 0) 228 return true; 229 match = null; 230 } 231 return false; 232 } 233 234 /** 235 * Attempts to match the entire input sequence against the pattern. 236 * 237 * If the match succeeds then more information can be obtained via the 238 * start, end, and group methods. 239 * 240 * @see #start 241 * @see #end 242 * @see #group 243 */ 244 public boolean matches() { 245 return find(0); 246 } 247 248 /** 249 * Returns the Pattern that is interpreted by this Matcher 250 */ 251 public Pattern pattern() { 252 return pattern; 253 } 254 255 /** 256 * Resets this matcher. 257 * <p> 258 * Resetting a matcher discards all of its explicit state information and sets its append 259 * position to zero. 260 * 261 * @return This matcher 262 */ 263 public Matcher reset() { 264 position = 0; 265 match = null; 266 return this; 267 } 268 269 /** 270 * @param input The new input character sequence 271 */ 272 public Matcher reset(StringBuffer input) { 273 this.input = input; 274 return reset(); 275 } 276 277 /** 278 * @param group The index of a capturing group in this matcher's pattern 279 * 280 * @exception IllegalStateException If no match has yet been attempted, 281 * or if the previous match operation failed 282 */ 283 public int start() throws IllegalStateException { 284 assertMatchOp(); 285 return match.getStartIndex(); 286 } 287 288 /** 289 * @param group The index of a capturing group in this matcher's pattern 290 * 291 * @exception IllegalStateException If no match has yet been attempted, 292 * or if the previous match operation failed 293 * @exception IndexOutOfBoundsException If the replacement string refers 294 * to a capturing group that does not exist in the pattern 295 */ 296 public int start(int group) throws IllegalStateException { 297 assertMatchOp(); 298 return match.getStartIndex(group); 299 } 300 301 private void assertMatchOp() { 302 if (match == null) 303 throw new IllegalStateException(); 304 } 305}