KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > proguard > util > BasicMatcher


1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  * of Java bytecode.
4  *
5  * Copyright (c) 2002 Eric Lafortune (eric@graphics.cornell.edu)
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */

21 package proguard.util;
22
23 import java.util.*;
24
25 /**
26  * This StringMatcher tests whether strings match a given regular
27  * expression. Supported wildcards are
28  * <ul>
29  * <li>'?' for a single Java identifier character or other wildcard
30  * matching character,
31  * <li>'*' for any number of Java identifier characters or other wildcard
32  * matching characters, and
33  * <li>'**' for any number of Java identifier characters or extended wildcard
34  * matching characters,
35  * <li>'%' for a single special wildcard matching character.
36  * </ul>
37  * The sets of wildcard characters, extended wildcard characters, and special
38  * wildcard characters can be defined by the user.
39  *
40  * @author Eric Lafortune
41  */

42 public class BasicMatcher implements StringMatcher
43 {
44     private static final String JavaDoc SINGLE_CHARACTER_WILDCARD = "?";
45     private static final String JavaDoc MULTIPLE_CHARACTERS_WILDCARD1 = "*";
46     private static final String JavaDoc MULTIPLE_CHARACTERS_WILDCARD2 = "**";
47     private static final String JavaDoc SPECIAL_CHARACTER_WILDCARD = "%";
48
49     private String JavaDoc[] expressionParts;
50     private char[] wildcardCharacters;
51     private char[] extendedWildcardCharacters;
52     private char[] specialWildcardCharacters;
53
54
55     /**
56      * Creates a new BasicMatcher without extra wildcard matching
57      * characters.
58      * @param regularExpression the regular expression against which strings
59      * will be matched.
60      */

61     public BasicMatcher(String JavaDoc regularExpression)
62     {
63         this(regularExpression, null, null, null);
64     }
65
66
67     /**
68      * Creates a new BasicMatcher.
69      * @param regularExpression the regular expression against which
70      * strings will be matched.
71      * @param wildcardCharacters an optional extra list of wildcard
72      * matching characters.
73      * @param extendedWildcardCharacters an optional extra list of extended
74      * wildcard matching characters.
75      */

76     public BasicMatcher(String JavaDoc regularExpression,
77                         char[] wildcardCharacters,
78                         char[] extendedWildcardCharacters,
79                         char[] specialWildcardCharacters)
80     {
81         this.wildcardCharacters = wildcardCharacters;
82         this.extendedWildcardCharacters = extendedWildcardCharacters;
83         this.specialWildcardCharacters = specialWildcardCharacters;
84
85         // Split the given regular expression into an array of parts: "?",
86
// "*", "**", "%", and simple text strings.
87

88         // A List to collect the subsequent regular expression parts.
89
List expressionPartsList = new ArrayList();
90
91         String JavaDoc wildcard = null;
92         int previousIndex = 0;
93         int index = 0;
94         int regularExpressionLength = regularExpression.length();
95         while (index < regularExpressionLength)
96         {
97             wildcard =
98                 regularExpression.regionMatches(index, MULTIPLE_CHARACTERS_WILDCARD2, 0, MULTIPLE_CHARACTERS_WILDCARD2.length()) ? MULTIPLE_CHARACTERS_WILDCARD2 :
99                 regularExpression.regionMatches(index, MULTIPLE_CHARACTERS_WILDCARD1, 0, MULTIPLE_CHARACTERS_WILDCARD1.length()) ? MULTIPLE_CHARACTERS_WILDCARD1 :
100                 regularExpression.regionMatches(index, SINGLE_CHARACTER_WILDCARD, 0, SINGLE_CHARACTER_WILDCARD.length()) ? SINGLE_CHARACTER_WILDCARD :
101                 regularExpression.regionMatches(index, SPECIAL_CHARACTER_WILDCARD, 0, SINGLE_CHARACTER_WILDCARD.length()) ? SPECIAL_CHARACTER_WILDCARD :
102                                                                                                                                    null;
103             if (wildcard != null)
104             {
105                 // Add the simple text string that we've skipped.
106
if (previousIndex < index)
107                 {
108                     expressionPartsList.add(regularExpression.substring(previousIndex, index));
109                 }
110
111                 // Add the wildcard that we've found.
112
expressionPartsList.add(wildcard);
113
114                 // We'll continue parsing after this wildcard.
115
index += wildcard.length();
116                 previousIndex = index;
117             }
118             else
119             {
120                 // We'll continue parsing at the next character.
121
index++;
122             }
123         }
124
125         // Add the final simple text string that we've skipped, if any.
126
if (wildcard == null)
127         {
128             expressionPartsList.add(regularExpression.substring(previousIndex));
129         }
130
131         // Copy the List into the array.
132
expressionParts = new String JavaDoc[expressionPartsList.size()];
133         expressionPartsList.toArray(expressionParts);
134     }
135
136
137     // Implementations for StringMatcher.
138

139     public boolean matches(String JavaDoc string)
140     {
141         return matches(string, 0, 0);
142     }
143
144
145     /**
146      * Tries to match the given string, starting at the given index, with the
147      * regular expression parts starting at the given index.
148      */

149     private boolean matches(String JavaDoc string,
150                             int stringStartIndex,
151                             int expressionIndex)
152     {
153         // Are we out of expression parts?
154
if (expressionIndex == expressionParts.length)
155         {
156             // There's a match, at least if we're at the end of the string as well.
157
return stringStartIndex == string.length();
158         }
159
160         String JavaDoc expressionPart = expressionParts[expressionIndex];
161
162         // Did we get a wildcard of some sort?
163
if (expressionPart.equals(SINGLE_CHARACTER_WILDCARD))
164         {
165             // Do we have any characters left to match?
166
if (stringStartIndex == string.length())
167             {
168                 // We've run out of characters.
169
return false;
170             }
171
172             // Make sure we're matching an allowed character and then check if
173
// the rest of the expression parts match.
174
return
175                 matchesWildcard(string.charAt(stringStartIndex)) &&
176                 matches(string, stringStartIndex + 1, expressionIndex + 1);
177         }
178         else if (expressionPart.equals(MULTIPLE_CHARACTERS_WILDCARD1))
179         {
180             // Try out all possible matches for '*', not matching the package
181
// separator.
182
for (int stringEndIndex = stringStartIndex;
183                  stringEndIndex <= string.length();
184                  stringEndIndex++)
185             {
186                 // Are we matching some characters already?
187
if (stringEndIndex > stringStartIndex)
188                 {
189                     // Make sure we don't start matching the wrong characters.
190
if (!matchesWildcard(string.charAt(stringEndIndex-1)))
191                     {
192                         // We can never get a match.
193
return false;
194                     }
195                 }
196
197                 // Continue looking for a match of the next expression part,
198
// starting from the end index.
199
if (matches(string, stringEndIndex, expressionIndex + 1))
200                 {
201                     return true;
202                 }
203             }
204
205             // We could get a match for '*', but not for the rest of the
206
// expression parts.
207
return false;
208         }
209         else if (expressionPart.equals(MULTIPLE_CHARACTERS_WILDCARD2))
210         {
211             // Try out all possible matches for '**'.
212
for (int stringEndIndex = stringStartIndex;
213                  stringEndIndex <= string.length();
214                  stringEndIndex++)
215             {
216                 // Are we matching some characters already?
217
if (stringEndIndex > stringStartIndex)
218                 {
219                     // Make sure we don't start matching the wrong characters.
220
if (!matchesExtendedWildcard(string.charAt(stringEndIndex-1)))
221                     {
222                         // We can never get a match.
223
return false;
224                     }
225                 }
226
227                 // Continue looking for a match of the next expression part,
228
// starting from this index.
229
if (matches(string, stringEndIndex, expressionIndex + 1))
230                 {
231                     return true;
232                 }
233             }
234
235             // We could get a match for '**', but not for the rest of the
236
// expression parts.
237
return stringStartIndex == string.length();
238         }
239         else if (expressionPart.equals(SPECIAL_CHARACTER_WILDCARD))
240         {
241             // Do we have any characters left to match?
242
if (stringStartIndex == string.length())
243             {
244                 // We've run out of characters.
245
return false;
246             }
247
248             // Make sure we're matching an allowed character and then check if
249
// the rest of the expression parts match.
250
return
251                 matchesSpecialWildcard(string.charAt(stringStartIndex)) &&
252                 matches(string, stringStartIndex + 1, expressionIndex + 1);
253         }
254         else
255         {
256             // The expression part is a simple text string. Check if it matches,
257
// and if the rest of the expression parts match.
258
int expressionPartLength = expressionPart.length();
259             return
260                 string.regionMatches(stringStartIndex, expressionPart, 0, expressionPartLength) &&
261                 matches(string, stringStartIndex + expressionPartLength, expressionIndex + 1);
262         }
263     }
264
265
266     /**
267      * Returns whether the given character matches a simple '?' or '*' wildcard.
268      */

269     private boolean matchesWildcard(char character)
270     {
271         if (Character.isJavaIdentifierPart(character))
272         {
273             return true;
274         }
275
276         if (wildcardCharacters != null)
277         {
278             for (int index = 0; index < wildcardCharacters.length; index++)
279             {
280                 if (character == wildcardCharacters[index])
281                 {
282                     return true;
283                 }
284             }
285         }
286
287         return false;
288     }
289
290
291     /**
292      * Returns whether the given character matches an extended '**' wildcard.
293      */

294     private boolean matchesExtendedWildcard(char character)
295     {
296         if (matchesWildcard(character))
297         {
298             return true;
299         }
300
301         if (extendedWildcardCharacters != null)
302         {
303             for (int index = 0; index < extendedWildcardCharacters.length; index++)
304             {
305                 if (character == extendedWildcardCharacters[index])
306                 {
307                     return true;
308                 }
309             }
310         }
311
312         return false;
313     }
314
315
316     /**
317      * Returns whether the given character matches a special '%' wildcard.
318      */

319     private boolean matchesSpecialWildcard(char character)
320     {
321         if (specialWildcardCharacters != null)
322         {
323             for (int index = 0; index < specialWildcardCharacters.length; index++)
324             {
325                 if (character == specialWildcardCharacters[index])
326                 {
327                     return true;
328                 }
329             }
330         }
331
332         return false;
333     }
334
335
336     /**
337      * A main method for testing string matching.
338      */

339     public static void main(String JavaDoc[] args)
340     {
341         try
342         {
343             System.out.println("Regular expression ["+args[0]+"]");
344             BasicMatcher matcher =
345                 new BasicMatcher(args[0], null, new char[] {'/'}, null);
346
347             for (int index = 1; index < args.length; index++)
348             {
349                 String JavaDoc string = args[index];
350                 System.out.print("String ["+string+"]");
351                 System.out.println(" -> match = "+matcher.matches(args[index]));
352             }
353         }
354         catch (Exception JavaDoc ex)
355         {
356             ex.printStackTrace();
357         }
358     }
359 }
360
Popular Tags