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