View Javadoc

1   package org.apache.commons.digester3;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  
25  /**
26   * <p>
27   * Simple regex pattern matching algorithm.
28   * </p>
29   * <p>
30   * This uses just two wildcards:
31   * <ul>
32   * <li><code>*</code> matches any sequence of none, one or more characters
33   * <li><code>?</code> matches any one character
34   * </ul>
35   * Escaping these wildcards is not supported .
36   * </p>
37   * 
38   * @since 1.5
39   */
40  public class SimpleRegexMatcher
41      extends RegexMatcher
42  {
43  
44      // --------------------------------------------------------- Fields
45  
46      /** Default log (class wide) */
47      private static final Log BASE_LOG = LogFactory.getLog( SimpleRegexMatcher.class );
48  
49      /** Custom log (can be set per object) */
50      private Log log = BASE_LOG;
51  
52      // --------------------------------------------------------- Properties
53  
54      /**
55       * Gets the <code>Log</code> implementation.
56       *
57       * @return the <code>Log</code> implementation.
58       */
59      public Log getLog()
60      {
61          return log;
62      }
63  
64      /**
65       * Sets the current <code>Log</code> implementation used by this class.
66       *
67       * @param log the current <code>Log</code> implementation used by this class.
68       */
69      public void setLog( Log log )
70      {
71          this.log = log;
72      }
73  
74      // --------------------------------------------------------- Public Methods
75  
76      /**
77       * {@inheritDoc}
78       */
79      @Override
80      public boolean match( String basePattern, String regexPattern )
81      {
82          // check for nulls
83          if ( basePattern == null || regexPattern == null )
84          {
85              return false;
86          }
87          return match( basePattern, regexPattern, 0, 0 );
88      }
89  
90      // --------------------------------------------------------- Implementations Methods
91  
92      /**
93       * Implementation of regex matching algorithm. This calls itself recursively.
94       *
95       * @param basePattern the standard digester path representing the element
96       * @param regexPattern the regex pattern the path will be tested against
97       * @param baseAt FIXME
98       * @param regexAt FIXME
99       */
100     private boolean match( String basePattern, String regexPattern, int baseAt, int regexAt )
101     {
102         if ( log.isTraceEnabled() )
103         {
104             log.trace( "Base: " + basePattern );
105             log.trace( "Regex: " + regexPattern );
106             log.trace( "Base@" + baseAt );
107             log.trace( "Regex@" + regexAt );
108         }
109 
110         // check bounds
111         if ( regexAt >= regexPattern.length() )
112         {
113             // maybe we've got a match
114             if ( baseAt >= basePattern.length() )
115             {
116                 // ok!
117                 return true;
118             }
119             // run out early
120             return false;
121 
122         }
123         if ( baseAt >= basePattern.length() )
124         {
125             // run out early
126             return false;
127         }
128 
129         // ok both within bounds
130         char regexCurrent = regexPattern.charAt( regexAt );
131         switch ( regexCurrent )
132         {
133             case '*':
134                 // this is the tricky case
135                 // check for terminal
136                 if ( ++regexAt >= regexPattern.length() )
137                 {
138                     // this matches anything let - so return true
139                     return true;
140                 }
141                 // go through every subsequent apperance of the next character
142                 // and so if the rest of the regex matches
143                 char nextRegex = regexPattern.charAt( regexAt );
144                 if ( log.isTraceEnabled() )
145                 {
146                     log.trace( "Searching for next '" + nextRegex + "' char" );
147                 }
148                 int nextMatch = basePattern.indexOf( nextRegex, baseAt );
149                 while ( nextMatch != -1 )
150                 {
151                     if ( log.isTraceEnabled() )
152                     {
153                         log.trace( "Trying '*' match@" + nextMatch );
154                     }
155                     if ( match( basePattern, regexPattern, nextMatch, regexAt ) )
156                     {
157                         return true;
158                     }
159                     nextMatch = basePattern.indexOf( nextRegex, nextMatch + 1 );
160                 }
161                 log.trace( "No matches found." );
162                 return false;
163 
164             case '?':
165                 // this matches anything
166                 return match( basePattern, regexPattern, ++baseAt, ++regexAt );
167 
168             default:
169                 if ( log.isTraceEnabled() )
170                 {
171                     log.trace( "Camparing " + regexCurrent + " to " + basePattern.charAt( baseAt ) );
172                 }
173                 if ( regexCurrent == basePattern.charAt( baseAt ) )
174                 {
175                     // still got more to go
176                     return match( basePattern, regexPattern, ++baseAt, ++regexAt );
177                 }
178                 return false;
179         }
180     }
181 
182 }