001: /*
002: * gnu/regexp/RETokenRepeated.java
003: * Copyright (C) 1998 Wes Biggs
004: *
005: * This library is free software; you can redistribute it and/or modify
006: * it under the terms of the GNU Library General Public License as published
007: * by the Free Software Foundation; either version 2 of the License, or
008: * (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013: * GNU Library General Public License for more details.
014: *
015: * You should have received a copy of the GNU Library General Public License
016: * along with this program; if not, write to the Free Software
017: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
018: */
019:
020: package gnu.regexp;
021:
022: import java.util.Vector;
023:
024: class RETokenRepeated extends REToken {
025: private REToken token;
026: private int min, max;
027: private boolean stingy;
028:
029: RETokenRepeated(int f_subIndex, REToken f_token, int f_min,
030: int f_max) {
031: super (f_subIndex);
032: token = f_token;
033: min = f_min;
034: max = f_max;
035: }
036:
037: void makeStingy() {
038: stingy = true;
039: }
040:
041: int getMinimumLength() {
042: return (min * token.getMinimumLength());
043: }
044:
045: int[] match(CharIndexed input, int index, int eflags,
046: REMatch mymatch) {
047: int numRepeats = 0;
048: Vector positions = new Vector();
049: int[] newIndex = new int[] { index };
050: do {
051: // positions.elementAt(i) == position [] in input after <<i>> matches
052: positions.addElement(newIndex);
053:
054: // Check for stingy match for each possibility.
055: if (stingy && (numRepeats >= min)) {
056: for (int i = 0; i < newIndex.length; i++) {
057: int[] s = next(input, newIndex[i], eflags, mymatch);
058: if (s != null)
059: return s;
060: }
061: }
062:
063: int[] doables = new int[0];
064: int[] this Result;
065: for (int i = 0; i < newIndex.length; i++) {
066: if ((this Result = token.match(input, newIndex[i],
067: eflags, mymatch)) != null) {
068: // add to doables array
069: int[] temp = new int[doables.length
070: + this Result.length];
071: System.arraycopy(doables, 0, temp, 0,
072: doables.length);
073: for (int j = 0; j < this Result.length; j++) {
074: temp[doables.length + j] = this Result[j];
075: }
076: doables = temp;
077: }
078: }
079: if (doables.length == 0)
080: break;
081:
082: newIndex = doables;
083: } while (numRepeats++ < max);
084:
085: // If there aren't enough repeats, then fail
086: if (numRepeats < min)
087: return null;
088:
089: // We're greedy, but ease off until a true match is found
090: int posIndex = positions.size();
091:
092: // At this point we've either got too many or just the right amount.
093: // See if this numRepeats works with the rest of the regexp.
094: int[] doneIndex;
095: while (--posIndex >= min) {
096: newIndex = (int[]) positions.elementAt(posIndex);
097: // If rest of pattern matches
098: for (int i = 0; i < newIndex.length; i++)
099: if ((doneIndex = next(input, newIndex[i], eflags,
100: mymatch)) != null)
101: return doneIndex;
102:
103: // else did not match rest of the tokens, try again on smaller sample
104: }
105: return null;
106: }
107:
108: void dump(StringBuffer os) {
109: os.append('(');
110: if (token.m_subIndex == 0)
111: os.append("?:");
112: token.dumpAll(os);
113: os.append(')');
114: if ((max == Integer.MAX_VALUE) && (min <= 1))
115: os.append((min == 0) ? '*' : '+');
116: else if ((min == 0) && (max == 1))
117: os.append('?');
118: else {
119: os.append('{').append(min);
120: if (max > min) {
121: os.append(',');
122: if (max != Integer.MAX_VALUE)
123: os.append(max);
124: }
125: os.append('}');
126: }
127: if (stingy)
128: os.append('?');
129: }
130: }
|