source: src/main/java/agents/org/apache/commons/lang/CharRange.java

Last change on this file was 127, checked in by Wouter Pasman, 6 years ago

#41 ROLL BACK of rev.126 . So this version is equal to rev. 125

File size: 12.3 KB
Line 
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. 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 */
17package agents.org.apache.commons.lang;
18
19import java.io.Serializable;
20import java.util.Iterator;
21import java.util.NoSuchElementException;
22
23import agents.org.apache.commons.lang.text.StrBuilder;
24
25/**
26 * <p>A contiguous range of characters, optionally negated.</p>
27 *
28 * <p>Instances are immutable.</p>
29 *
30 * <p>#ThreadSafe#</p>
31 * @author Apache Software Foundation
32 * @author Chris Feldhacker
33 * @author Gary Gregory
34 * @since 1.0
35 * @version $Id: CharRange.java 1057072 2011-01-10 01:55:57Z niallp $
36 */
37public final class CharRange implements Serializable {
38
39 /**
40 * Required for serialization support. Lang version 2.0.
41 *
42 * @see java.io.Serializable
43 */
44 private static final long serialVersionUID = 8270183163158333422L;
45
46 /** The first character, inclusive, in the range. */
47 private final char start;
48 /** The last character, inclusive, in the range. */
49 private final char end;
50 /** True if the range is everything except the characters specified. */
51 private final boolean negated;
52
53 /** Cached toString. */
54 private transient String iToString;
55
56 // Static
57 //-----------------------------------------------------------------------
58 /**
59 * <p>Constructs a <code>CharRange</code> over a single character.</p>
60 *
61 * @param ch only character in this range
62 * @return the new CharRange object
63 * @see CharRange#CharRange(char, char, boolean)
64 * @since 2.5
65 */
66 public static CharRange is(char ch) {
67 return new CharRange(ch, ch, false);
68 }
69
70 /**
71 * <p>Constructs a negated <code>CharRange</code> over a single character.</p>
72 *
73 * @param ch only character in this range
74 * @return the new CharRange object
75 * @see CharRange#CharRange(char, char, boolean)
76 * @since 2.5
77 */
78 public static CharRange isNot(char ch) {
79 return new CharRange(ch, ch, true);
80 }
81
82 /**
83 * <p>Constructs a <code>CharRange</code> over a set of characters.</p>
84 *
85 * @param start first character, inclusive, in this range
86 * @param end last character, inclusive, in this range
87 * @return the new CharRange object
88 * @see CharRange#CharRange(char, char, boolean)
89 * @since 2.5
90 */
91 public static CharRange isIn(char start, char end) {
92 return new CharRange(start, end, false);
93 }
94
95 /**
96 * <p>Constructs a negated <code>CharRange</code> over a set of characters.</p>
97 *
98 * @param start first character, inclusive, in this range
99 * @param end last character, inclusive, in this range
100 * @return the new CharRange object
101 * @see CharRange#CharRange(char, char, boolean)
102 * @since 2.5
103 */
104 public static CharRange isNotIn(char start, char end) {
105 return new CharRange(start, end, true);
106 }
107
108 //-----------------------------------------------------------------------
109 /**
110 * <p>Constructs a <code>CharRange</code> over a single character.</p>
111 *
112 * @param ch only character in this range
113 */
114 public CharRange(char ch) {
115 this(ch, ch, false);
116 }
117
118 /**
119 * <p>Constructs a <code>CharRange</code> over a single character,
120 * optionally negating the range.</p>
121 *
122 * <p>A negated range includes everything except the specified char.</p>
123 *
124 * @param ch only character in this range
125 * @param negated true to express everything except the range
126 */
127 public CharRange(char ch, boolean negated) {
128 this(ch, ch, negated);
129 }
130
131 /**
132 * <p>Constructs a <code>CharRange</code> over a set of characters.</p>
133 *
134 * @param start first character, inclusive, in this range
135 * @param end last character, inclusive, in this range
136 */
137 public CharRange(char start, char end) {
138 this(start, end, false);
139 }
140
141 /**
142 * <p>Constructs a <code>CharRange</code> over a set of characters,
143 * optionally negating the range.</p>
144 *
145 * <p>A negated range includes everything except that defined by the
146 * start and end characters.</p>
147 *
148 * <p>If start and end are in the wrong order, they are reversed.
149 * Thus <code>a-e</code> is the same as <code>e-a</code>.</p>
150 *
151 * @param start first character, inclusive, in this range
152 * @param end last character, inclusive, in this range
153 * @param negated true to express everything except the range
154 */
155 public CharRange(char start, char end, boolean negated) {
156 super();
157 if (start > end) {
158 char temp = start;
159 start = end;
160 end = temp;
161 }
162
163 this.start = start;
164 this.end = end;
165 this.negated = negated;
166 }
167
168 // Accessors
169 //-----------------------------------------------------------------------
170 /**
171 * <p>Gets the start character for this character range.</p>
172 *
173 * @return the start char (inclusive)
174 */
175 public char getStart() {
176 return this.start;
177 }
178
179 /**
180 * <p>Gets the end character for this character range.</p>
181 *
182 * @return the end char (inclusive)
183 */
184 public char getEnd() {
185 return this.end;
186 }
187
188 /**
189 * <p>Is this <code>CharRange</code> negated.</p>
190 *
191 * <p>A negated range includes everything except that defined by the
192 * start and end characters.</p>
193 *
194 * @return <code>true</code> is negated
195 */
196 public boolean isNegated() {
197 return negated;
198 }
199
200 // Contains
201 //-----------------------------------------------------------------------
202 /**
203 * <p>Is the character specified contained in this range.</p>
204 *
205 * @param ch the character to check
206 * @return <code>true</code> if this range contains the input character
207 */
208 public boolean contains(char ch) {
209 return (ch >= start && ch <= end) != negated;
210 }
211
212 /**
213 * <p>Are all the characters of the passed in range contained in
214 * this range.</p>
215 *
216 * @param range the range to check against
217 * @return <code>true</code> if this range entirely contains the input range
218 * @throws IllegalArgumentException if <code>null</code> input
219 */
220 public boolean contains(CharRange range) {
221 if (range == null) {
222 throw new IllegalArgumentException("The Range must not be null");
223 }
224 if (negated) {
225 if (range.negated) {
226 return start >= range.start && end <= range.end;
227 }
228 return range.end < start || range.start > end;
229 }
230 if (range.negated) {
231 return start == 0 && end == Character.MAX_VALUE;
232 }
233 return start <= range.start && end >= range.end;
234 }
235
236 // Basics
237 //-----------------------------------------------------------------------
238 /**
239 * <p>Compares two CharRange objects, returning true if they represent
240 * exactly the same range of characters defined in the same way.</p>
241 *
242 * @param obj the object to compare to
243 * @return true if equal
244 */
245 public boolean equals(Object obj) {
246 if (obj == this) {
247 return true;
248 }
249 if (obj instanceof CharRange == false) {
250 return false;
251 }
252 CharRange other = (CharRange) obj;
253 return start == other.start && end == other.end && negated == other.negated;
254 }
255
256 /**
257 * <p>Gets a hashCode compatible with the equals method.</p>
258 *
259 * @return a suitable hashCode
260 */
261 public int hashCode() {
262 return 83 + start + 7 * end + (negated ? 1 : 0);
263 }
264
265 /**
266 * <p>Gets a string representation of the character range.</p>
267 *
268 * @return string representation of this range
269 */
270 public String toString() {
271 if (iToString == null) {
272 StrBuilder buf = new StrBuilder(4);
273 if (isNegated()) {
274 buf.append('^');
275 }
276 buf.append(start);
277 if (start != end) {
278 buf.append('-');
279 buf.append(end);
280 }
281 iToString = buf.toString();
282 }
283 return iToString;
284 }
285
286 // Expansions
287 //-----------------------------------------------------------------------
288 /**
289 * <p>Returns an iterator which can be used to walk through the characters described by this range.</p>
290 *
291 * <p>#NotThreadSafe# the iterator is not threadsafe</p>
292 * @return an iterator to the chars represented by this range
293 * @since 2.5
294 */
295 public Iterator iterator() {
296 return new CharacterIterator(this);
297 }
298
299 /**
300 * Character {@link Iterator}.
301 * <p>#NotThreadSafe#</p>
302 */
303 private static class CharacterIterator implements Iterator {
304 /** The current character */
305 private char current;
306
307 private final CharRange range;
308 private boolean hasNext;
309
310 /**
311 * Construct a new iterator for the character range.
312 *
313 * @param r The character range
314 */
315 private CharacterIterator(CharRange r) {
316 range = r;
317 hasNext = true;
318
319 if (range.negated) {
320 if (range.start == 0) {
321 if (range.end == Character.MAX_VALUE) {
322 // This range is an empty set
323 hasNext = false;
324 } else {
325 current = (char) (range.end + 1);
326 }
327 } else {
328 current = 0;
329 }
330 } else {
331 current = range.start;
332 }
333 }
334
335 /**
336 * Prepare the next character in the range.
337 */
338 private void prepareNext() {
339 if (range.negated) {
340 if (current == Character.MAX_VALUE) {
341 hasNext = false;
342 } else if (current + 1 == range.start) {
343 if (range.end == Character.MAX_VALUE) {
344 hasNext = false;
345 } else {
346 current = (char) (range.end + 1);
347 }
348 } else {
349 current = (char) (current + 1);
350 }
351 } else if (current < range.end) {
352 current = (char) (current + 1);
353 } else {
354 hasNext = false;
355 }
356 }
357
358 /**
359 * Has the iterator not reached the end character yet?
360 *
361 * @return <code>true</code> if the iterator has yet to reach the character date
362 */
363 public boolean hasNext() {
364 return hasNext;
365 }
366
367 /**
368 * Return the next character in the iteration
369 *
370 * @return <code>Character</code> for the next character
371 */
372 public Object next() {
373 if (hasNext == false) {
374 throw new NoSuchElementException();
375 }
376 char cur = current;
377 prepareNext();
378 return new Character(cur);
379 }
380
381 /**
382 * Always throws UnsupportedOperationException.
383 *
384 * @throws UnsupportedOperationException
385 * @see java.util.Iterator#remove()
386 */
387 public void remove() {
388 throw new UnsupportedOperationException();
389 }
390 }
391}
Note: See TracBrowser for help on using the repository browser.