001: /*
002: * Copyright (C) Chaperon. All rights reserved.
003: * -------------------------------------------------------------------------
004: * This software is published under the terms of the Apache Software License
005: * version 1.1, a copy of which has been included with this distribution in
006: * the LICENSE file.
007: */
008:
009: package net.sourceforge.chaperon.model.extended;
010:
011: import net.sourceforge.chaperon.common.Decoder;
012: import net.sourceforge.chaperon.common.SortedCharSet;
013: import net.sourceforge.chaperon.model.Violations;
014:
015: /**
016: * This class describes a pattern for a character class, which means the a character matches
017: * against a element of this class.
018: *
019: * @author <a href="mailto:stephan@apache.org">Stephan Michels</a>
020: * @version CVS $Id: CharacterClass.java,v 1.8 2004/01/07 08:28:49 benedikta Exp $
021: */
022: public class CharacterClass extends Pattern {
023: private SingleCharacter[] characters = new SingleCharacter[0];
024: private CharacterInterval[] intervals = new CharacterInterval[0];
025: private boolean exclusive = false;
026:
027: /**
028: * Creates a pattern for a character class.
029: */
030: public CharacterClass() {
031: }
032:
033: public void addSingleCharacter(SingleCharacter character) {
034: if (character == null)
035: return;
036:
037: SingleCharacter[] newCharacters = new SingleCharacter[characters.length + 1];
038: System.arraycopy(characters, 0, newCharacters, 0,
039: characters.length);
040: newCharacters[characters.length] = character;
041: characters = newCharacters;
042: }
043:
044: public SingleCharacter getSingleCharacter(int index) {
045: return characters[index];
046: }
047:
048: public SingleCharacter[] getSingleCharacters() {
049: return characters;
050: }
051:
052: public int getSingleCharacterCount() {
053: return characters.length;
054: }
055:
056: public void addCharacterInterval(CharacterInterval interval) {
057: if (interval == null)
058: return;
059:
060: CharacterInterval[] newIntervals = new CharacterInterval[intervals.length + 1];
061: System.arraycopy(intervals, 0, newIntervals, 0,
062: intervals.length);
063: newIntervals[intervals.length] = interval;
064: intervals = newIntervals;
065: }
066:
067: public CharacterInterval getCharacterInterval(int index) {
068: return intervals[index];
069: }
070:
071: public CharacterInterval[] getCharacterIntervals() {
072: return intervals;
073: }
074:
075: public int getCharacterIntervalCount() {
076: return intervals.length;
077: }
078:
079: /**
080: * If the comparing character must match to the elements, or should not match to the elements.
081: *
082: * @param exclusive If the character class should be exclusive.
083: */
084: public void setExclusive(boolean exclusive) {
085: this .exclusive = exclusive;
086: }
087:
088: /**
089: * If this character class is exclusive
090: *
091: * @return If the character class should be exclusive.
092: */
093: public boolean isExclusive() {
094: return exclusive;
095: }
096:
097: public boolean isNullable() {
098: return false;
099: }
100:
101: public PatternSet getFirstSet() {
102: PatternSet set = new PatternSet();
103: set.addPattern(this );
104: return set;
105: }
106:
107: public PatternSet getLastSet() {
108: PatternSet set = new PatternSet();
109: set.addPattern(this );
110: return set;
111: }
112:
113: public char[] getLimits() {
114: SortedCharSet limits = new SortedCharSet();
115: for (int i = 0; i < characters.length; i++)
116: limits.addChar(characters[i].getLimits());
117:
118: for (int i = 0; i < intervals.length; i++)
119: limits.addChar(intervals[i].getLimits());
120:
121: return limits.getChar();
122: }
123:
124: public boolean contains(char minimum, char maximum) {
125: if (!exclusive) {
126: for (int i = 0; i < characters.length; i++)
127: if (characters[i].contains(minimum, maximum))
128: return true;
129:
130: for (int i = 0; i < intervals.length; i++)
131: if (intervals[i].contains(minimum, maximum))
132: return true;
133:
134: return false;
135: }
136:
137: for (int i = 0; i < characters.length; i++)
138: if (characters[i].contains(minimum, maximum))
139: return false;
140:
141: for (int i = 0; i < intervals.length; i++)
142: if (intervals[i].contains(minimum, maximum))
143: return false;
144:
145: return true;
146: }
147:
148: public boolean contains(char c) {
149: if (!exclusive) {
150: for (int i = 0; i < characters.length; i++)
151: if (characters[i].contains(c))
152: return true;
153:
154: for (int i = 0; i < intervals.length; i++)
155: if (intervals[i].contains(c))
156: return true;
157:
158: return false;
159: }
160:
161: for (int i = 0; i < characters.length; i++)
162: if (characters[i].contains(c))
163: return false;
164:
165: for (int i = 0; i < intervals.length; i++)
166: if (intervals[i].contains(c))
167: return false;
168:
169: return true;
170: }
171:
172: public String getSymbol() {
173: return null;
174: }
175:
176: /**
177: * Create a clone of this pattern.
178: *
179: * @return Clone of this pattern.
180: *
181: * @throws CloneNotSupportedException If an exception occurs during the cloning.
182: */
183: public String toString() {
184: StringBuffer buffer = new StringBuffer();
185:
186: buffer.append("[");
187:
188: if (exclusive)
189: buffer.append("^");
190:
191: for (int i = 0; i < characters.length; i++)
192: buffer.append(Decoder.decode(characters[i].getCharacter(),
193: Decoder.CLASS));
194:
195: for (int i = 0; i < intervals.length; i++) {
196: buffer
197: .append(Decoder.decode(intervals[i]
198: .getFirstCharacter().getCharacter(),
199: Decoder.CLASS));
200: buffer.append("-");
201: buffer.append(Decoder.decode(intervals[i]
202: .getLastCharacter().getCharacter(), Decoder.CLASS));
203: }
204:
205: buffer.append("]");
206:
207: buffer.append("[");
208: buffer.append(index);
209: buffer.append("]");
210:
211: return buffer.toString();
212: }
213:
214: /**
215: * Create a clone of this pattern.
216: *
217: * @return Clone of this pattern.
218: *
219: * @throws CloneNotSupportedException If an exception occurs during the cloning.
220: */
221: public Object clone() {
222: CharacterClass clone = new CharacterClass();
223:
224: for (int i = 0; i < characters.length; i++)
225: clone.addSingleCharacter(characters[i]);
226:
227: for (int i = 0; i < intervals.length; i++)
228: clone.addCharacterInterval(intervals[i]);
229:
230: clone.setExclusive(isExclusive());
231:
232: return clone;
233: }
234:
235: /**
236: * Validates this pattern.
237: *
238: * @return Return a list of violations, if this pattern isn't valid.
239: */
240: public Violations validate() {
241: Violations violations = new Violations();
242:
243: if ((characters.length + intervals.length) == 0)
244: violations.addViolation("Character class is empty",
245: getLocation());
246:
247: for (int i = 0; i < characters.length; i++)
248: violations.addViolations(characters[i].validate());
249:
250: for (int i = 0; i < intervals.length; i++)
251: violations.addViolations(intervals[i].validate());
252:
253: return violations;
254: }
255: }
|