1 package net.sourceforge.phpdt.externaltools.model;
3 /**********************************************************************
4 Copyright (c) 2000, 2002 IBM Corp. All rights reserved.
5 This file is made available under the terms of the Common Public License v1.0
6 which accompanies this distribution, and is available at
7 http://www.eclipse.org/legal/cpl-v10.html
8 **********************************************************************/
10 import java.util.Vector;
13 * Copied from net.sourceforge.phpdt.internal.ui.util.StringMatcher
15 * A string pattern matcher, suppporting * and ? wildcards.
17 public class StringMatcher {
18 protected String fPattern;
20 protected int fLength; // pattern length
22 protected boolean fIgnoreWildCards;
24 protected boolean fIgnoreCase;
26 protected boolean fHasLeadingStar;
28 protected boolean fHasTrailingStar;
30 protected String fSegments[]; // the given pattern is split into *
33 /* boundary value beyond which we don't need to search in the text */
34 protected int fBound = 0;
36 protected static final char fSingleWildCard = '\u0000';
38 public static class Position {
39 int start; // inclusive
43 public Position(int start, int end) {
48 public int getStart() {
58 * StringMatcher constructor takes in a String object that is a simple
59 * pattern which may contain �*� for 0 and many characters and �?� for
60 * exactly one character.
62 * Literal '*' and '?' characters must be escaped in the pattern e.g., "\*"
63 * means literal "*", etc.
65 * Escaping any other character (including the escape character itself),
66 * just results in that character in the pattern. e.g., "\a" means "a" and
69 * If invoking the StringMatcher with string literals in Java, don't forget
70 * escape characters are represented by "\\".
73 * the pattern to match text against
75 * if true, case is ignored
76 * @param ignoreWildCards
77 * if true, wild cards and their escape sequences are ignored
78 * (everything is taken literally).
80 public StringMatcher(String pattern, boolean ignoreCase,
81 boolean ignoreWildCards) {
83 throw new IllegalArgumentException();
84 fIgnoreCase = ignoreCase;
85 fIgnoreWildCards = ignoreWildCards;
87 fLength = pattern.length();
89 if (fIgnoreWildCards) {
97 * Find the first occurrence of the pattern between
98 * <code>start</code)(inclusive)
99 * and <code>end</code>(exclusive).
100 * @param <code>text</code>, the String object to search in
101 * @param <code>start</code>, the starting index of the search range, inclusive
102 * @param <code>end</code>, the ending index of the search range, exclusive
103 * @return an <code>StringMatcher.Position</code> object that keeps the starting
104 * (inclusive) and ending positions (exclusive) of the first occurrence of the
105 * pattern in the specified range of the text; return null if not found or subtext
106 * is empty (start==end). A pair of zeros is returned if pattern is empty string
107 * Note that for pattern like "*abc*" with leading and trailing stars, position of "abc"
108 * is returned. For a pattern like"*??*" in text "abcdf", (1,3) is returned
110 public StringMatcher.Position find(String text, int start, int end) {
112 throw new IllegalArgumentException();
114 int tlen = text.length();
119 if (end < 0 || start >= end)
122 return new Position(start, start);
123 if (fIgnoreWildCards) {
124 int x = posIn(text, start, end);
127 return new Position(x, x + fLength);
130 int segCount = fSegments.length;
131 if (segCount == 0)// pattern contains only '*'(s)
132 return new Position(start, end);
137 for (i = 0; i < segCount && curPos < end; ++i) {
138 String current = fSegments[i];
139 int nextMatch = regExpPosIn(text, curPos, end, current);
143 matchStart = nextMatch;
144 curPos = nextMatch + current.length();
148 return new Position(matchStart, curPos);
152 * match the given <code>text</code> with the pattern
154 * @return true if matched eitherwise false
155 * @param <code>text</code>, a String object
157 public boolean match(String text) {
158 return match(text, 0, text.length());
162 * Given the starting (inclusive) and the ending (exclusive) positions in
163 * the <code>text</code>, determine if the given substring matches with
166 * @return true if the specified portion of the text matches the pattern
168 * <code>text</code>, a String object that contains the
171 * <code>start<code> marks the starting position (inclusive) of the substring
172 * @param int <code>end<code> marks the ending index (exclusive) of the substring
174 public boolean match(String text, int start, int end) {
176 throw new IllegalArgumentException();
181 if (fIgnoreWildCards)
182 return (end - start == fLength)
183 && fPattern.regionMatches(fIgnoreCase, 0, text, start,
185 int segCount = fSegments.length;
186 if (segCount == 0 && (fHasLeadingStar || fHasTrailingStar)) // pattern
196 int tlen = text.length();
203 int bound = end - fBound;
207 String current = fSegments[i];
208 int segLength = current.length();
210 /* process first segment */
211 if (!fHasLeadingStar) {
212 if (!regExpRegionMatches(text, start, current, 0, segLength)) {
216 tCurPos = tCurPos + segLength;
220 /* process middle segments */
221 while (i < segCount) {
222 current = fSegments[i];
224 int k = current.indexOf(fSingleWildCard);
226 currentMatch = textPosIn(text, tCurPos, end, current);
227 if (currentMatch < 0)
230 currentMatch = regExpPosIn(text, tCurPos, end, current);
231 if (currentMatch < 0)
234 tCurPos = currentMatch + current.length();
238 /* process final segment */
239 if (!fHasTrailingStar && tCurPos != end) {
240 int clen = current.length();
241 return regExpRegionMatches(text, end - clen, current, 0, clen);
243 return i == segCount;
247 * This method parses the given pattern into segments seperated by wildcard
248 * '*' characters. Since wildcards are not being used in this case, the
249 * pattern consists of a single segment.
251 private void parseNoWildCards() {
252 fSegments = new String[1];
253 fSegments[0] = fPattern;
258 * Parses the given pattern into segments seperated by wildcard '*'
262 * a String object that is a simple regular expression with �*�
265 private void parseWildCards() {
266 if (fPattern.startsWith("*"))//$NON-NLS-1$
267 fHasLeadingStar = true;
268 if (fPattern.endsWith("*")) {//$NON-NLS-1$
269 /* make sure it's not an escaped wildcard */
270 if (fLength > 1 && fPattern.charAt(fLength - 2) != '\\') {
271 fHasTrailingStar = true;
275 Vector temp = new Vector();
278 StringBuffer buf = new StringBuffer();
279 while (pos < fLength) {
280 char c = fPattern.charAt(pos++);
283 if (pos >= fLength) {
286 char next = fPattern.charAt(pos++);
287 /* if it's an escape sequence */
288 if (next == '*' || next == '?' || next == '\\') {
291 /* not an escape sequence, just insert literally */
298 if (buf.length() > 0) {
300 temp.addElement(buf.toString());
301 fBound += buf.length();
306 /* append special character representing single match wildcard */
307 buf.append(fSingleWildCard);
314 /* add last buffer to segment list */
315 if (buf.length() > 0) {
316 temp.addElement(buf.toString());
317 fBound += buf.length();
320 fSegments = new String[temp.size()];
321 temp.copyInto(fSegments);
325 * @param <code>text</code>, a string which contains no wildcard
326 * @param <code>start</code>, the starting index in the text for search,
328 * @param <code>end</code>, the stopping point of search, exclusive
329 * @return the starting index in the text of the pattern , or -1 if not
332 protected int posIn(String text, int start, int end) {// no wild card in
334 int max = end - fLength;
337 int i = text.indexOf(fPattern, start);
338 if (i == -1 || i > max)
343 for (int i = start; i <= max; ++i) {
344 if (text.regionMatches(true, i, fPattern, 0, fLength))
352 * @param <code>text</code>, a simple regular expression that may only
354 * @param <code>start</code>, the starting index in the text for search,
356 * @param <code>end</code>, the stopping point of search, exclusive
357 * @param <code>p</code>, a simple regular expression that may contains '?'
358 * @param <code>caseIgnored</code>, wether the pattern is not casesensitive
359 * @return the starting index in the text of the pattern , or -1 if not
362 protected int regExpPosIn(String text, int start, int end, String p) {
363 int plen = p.length();
365 int max = end - plen;
366 for (int i = start; i <= max; ++i) {
367 if (regExpRegionMatches(text, i, p, 0, plen))
376 * @param <code>text</code>, a String to match
377 * @param <code>start</code>, int that indicates the starting index of
379 * @param <code>end</code> int that indicates the ending index of match,
381 * @param <code>p</code>, String, String, a simple regular expression that
383 * @param <code>ignoreCase</code>, boolean indicating wether code>p</code>
386 protected boolean regExpRegionMatches(String text, int tStart, String p,
387 int pStart, int plen) {
389 char tchar = text.charAt(tStart++);
390 char pchar = p.charAt(pStart++);
392 /* process wild cards */
393 if (!fIgnoreWildCards) {
394 /* skip single wild cards */
395 if (pchar == fSingleWildCard) {
402 if (Character.toUpperCase(tchar) == Character
405 // comparing after converting to upper case doesn't handle all
407 // also compare after converting to lower case
408 if (Character.toLowerCase(tchar) == Character
418 * @param <code>text</code>, the string to match
419 * @param <code>start</code>, the starting index in the text for search,
421 * @param <code>end</code>, the stopping point of search, exclusive
423 * </code>, a string that has no wildcard
425 * ignoreCase</code>, boolean indicating wether code>p</code>
427 * @return the starting index in the text of the pattern , or -1 if not
430 protected int textPosIn(String text, int start, int end, String p) {
432 int plen = p.length();
433 int max = end - plen;
436 int i = text.indexOf(p, start);
437 if (i == -1 || i > max)
442 for (int i = start; i <= max; ++i) {
443 if (text.regionMatches(true, i, p, 0, plen))