PageRenderTime 43ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-0-pre5/gnu/regexp/RETokenRepeated.java

#
Java | 207 lines | 125 code | 24 blank | 58 comment | 48 complexity | 96c761d3132eda4406b3140f292eeaa3 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * gnu/regexp/RETokenRepeated.java
  3. * Copyright (C) 1998-2001 Wes Biggs
  4. *
  5. * This library is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU Lesser General Public License as published
  7. * by the Free Software Foundation; either version 2.1 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This library is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Lesser General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Lesser General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. */
  19. package gnu.regexp;
  20. import java.util.Vector;
  21. final class RETokenRepeated extends REToken {
  22. private REToken token;
  23. private int min,max;
  24. private boolean stingy;
  25. RETokenRepeated(int subIndex, REToken token, int min, int max) {
  26. super(subIndex);
  27. this.token = token;
  28. this.min = min;
  29. this.max = max;
  30. }
  31. /** Sets the minimal matching mode to true. */
  32. void makeStingy() {
  33. stingy = true;
  34. }
  35. /** Queries if this token has minimal matching enabled. */
  36. boolean isStingy() {
  37. return stingy;
  38. }
  39. /**
  40. * The minimum length of a repeated token is the minimum length
  41. * of the token multiplied by the minimum number of times it must
  42. * match.
  43. */
  44. int getMinimumLength() {
  45. return (min * token.getMinimumLength());
  46. }
  47. // We do need to save every possible point, but the number of clone()
  48. // invocations here is really a killer for performance on non-stingy
  49. // repeat operators. I'm open to suggestions...
  50. // Hypothetical question: can you have a RE that matches 1 times,
  51. // 3 times, 5 times, but not 2 times or 4 times? Does having
  52. // the subexpression back-reference operator allow that?
  53. boolean match(CharIndexed input, REMatch mymatch) {
  54. // number of times we've matched so far
  55. int numRepeats = 0;
  56. // Possible positions for the next repeat to match at
  57. REMatch newMatch = mymatch;
  58. REMatch last = null;
  59. REMatch current;
  60. // Add the '0-repeats' index
  61. // positions.elementAt(z) == position [] in input after <<z>> matches
  62. Vector positions = new Vector();
  63. positions.addElement(newMatch);
  64. // Declare variables used in loop
  65. REMatch doables;
  66. REMatch doablesLast;
  67. REMatch recurrent;
  68. do {
  69. // Check for stingy match for each possibility.
  70. if (stingy && (numRepeats >= min)) {
  71. REMatch result = matchRest(input, newMatch);
  72. if (result != null) {
  73. mymatch.assignFrom(result);
  74. return true;
  75. }
  76. }
  77. doables = null;
  78. doablesLast = null;
  79. // try next repeat at all possible positions
  80. for (current = newMatch; current != null; current = current.next) {
  81. recurrent = (REMatch) current.clone();
  82. if (token.match(input, recurrent)) {
  83. // add all items in current to doables array
  84. if (doables == null) {
  85. doables = recurrent;
  86. doablesLast = recurrent;
  87. } else {
  88. // Order these from longest to shortest
  89. // Start by assuming longest (more repeats)
  90. doablesLast.next = recurrent;
  91. }
  92. // Find new doablesLast
  93. while (doablesLast.next != null) {
  94. doablesLast = doablesLast.next;
  95. }
  96. }
  97. }
  98. // if none of the possibilities worked out, break out of do/while
  99. if (doables == null) break;
  100. // reassign where the next repeat can match
  101. newMatch = doables;
  102. // increment how many repeats we've successfully found
  103. ++numRepeats;
  104. positions.addElement(newMatch);
  105. } while (numRepeats < max);
  106. // If there aren't enough repeats, then fail
  107. if (numRepeats < min) return false;
  108. // We're greedy, but ease off until a true match is found
  109. int posIndex = positions.size();
  110. // At this point we've either got too many or just the right amount.
  111. // See if this numRepeats works with the rest of the regexp.
  112. REMatch allResults = null;
  113. REMatch allResultsLast = null;
  114. REMatch results = null;
  115. while (--posIndex >= min) {
  116. newMatch = (REMatch) positions.elementAt(posIndex);
  117. results = matchRest(input, newMatch);
  118. if (results != null) {
  119. if (allResults == null) {
  120. allResults = results;
  121. allResultsLast = results;
  122. } else {
  123. // Order these from longest to shortest
  124. // Start by assuming longest (more repeats)
  125. allResultsLast.next = results;
  126. }
  127. // Find new doablesLast
  128. while (allResultsLast.next != null) {
  129. allResultsLast = allResultsLast.next;
  130. }
  131. }
  132. // else did not match rest of the tokens, try again on smaller sample
  133. }
  134. if (allResults != null) {
  135. mymatch.assignFrom(allResults); // does this get all?
  136. return true;
  137. }
  138. // If we fall out, no matches.
  139. return false;
  140. }
  141. private REMatch matchRest(CharIndexed input, final REMatch newMatch) {
  142. REMatch current, single;
  143. REMatch doneIndex = null;
  144. REMatch doneIndexLast = null;
  145. // Test all possible matches for this number of repeats
  146. for (current = newMatch; current != null; current = current.next) {
  147. // clone() separates a single match from the chain
  148. single = (REMatch) current.clone();
  149. if (next(input, single)) {
  150. // chain results to doneIndex
  151. if (doneIndex == null) {
  152. doneIndex = single;
  153. doneIndexLast = single;
  154. } else {
  155. doneIndexLast.next = single;
  156. }
  157. // Find new doneIndexLast
  158. while (doneIndexLast.next != null) {
  159. doneIndexLast = doneIndexLast.next;
  160. }
  161. }
  162. }
  163. return doneIndex;
  164. }
  165. void dump(StringBuffer os) {
  166. os.append("(?:");
  167. token.dumpAll(os);
  168. os.append(')');
  169. if ((max == Integer.MAX_VALUE) && (min <= 1))
  170. os.append( (min == 0) ? '*' : '+' );
  171. else if ((min == 0) && (max == 1))
  172. os.append('?');
  173. else {
  174. os.append('{').append(min);
  175. if (max > min) {
  176. os.append(',');
  177. if (max != Integer.MAX_VALUE) os.append(max);
  178. }
  179. os.append('}');
  180. }
  181. if (stingy) os.append('?');
  182. }
  183. }