diff --git a/src/main/java/org/apache/commons/lang3/CharRange.java b/src/main/java/org/apache/commons/lang3/CharRange.java index f63c8a56d..8cff4bf6f 100644 --- a/src/main/java/org/apache/commons/lang3/CharRange.java +++ b/src/main/java/org/apache/commons/lang3/CharRange.java @@ -17,6 +17,8 @@ package org.apache.commons.lang3; import java.io.Serializable; +import java.util.Iterator; +import java.util.NoSuchElementException; /** *
A contiguous range of characters, optionally negated.
@@ -241,5 +243,96 @@ public final class CharRange implements Serializable { } return iToString; } - + + // Expansions + //----------------------------------------------------------------------- + /** + *Returns an iterator which can be used to walk through the characters described by this range.
+ * + * @return an iterator to the chars represented by this range + */ + public Iterator iterator() { + return new CharacterIterator(this); + } + + static class CharacterIterator implements Iterator { + /** The currect character */ + private char current; + + private CharRange range; + private boolean hasNext; + + public CharacterIterator(CharRange r) { + range = r; + hasNext = true; + + if (range.negated) { + if (range.start == 0) { + if (range.end == Character.MAX_VALUE) { + // This range is an empty set + hasNext = false; + } else { + current = (char) (range.end + 1); + } + } else { + current = 0; + } + } else { + current = range.start; + } + } + + private void prepareNext() { + if (range.negated) { + if (current == Character.MAX_VALUE) { + hasNext = false; + } else if (current + 1 == range.start) { + if (range.end == Character.MAX_VALUE) { + hasNext = false; + } else { + current = (char) (range.end + 1); + } + } else { + current = (char) (current + 1); + } + } else if (current < range.end) { + current = (char) (current + 1); + } else { + hasNext = false; + } + } + + /** + * Has the iterator not reached the end character yet? + * + * @returntrue
if the iterator has yet to reach the character date
+ */
+ public boolean hasNext() {
+ return hasNext;
+ }
+
+ /**
+ * Return the next character in the iteration
+ *
+ * @return Character
for the next character
+ */
+ public Object next() {
+ if (hasNext == false) {
+ throw new NoSuchElementException();
+ }
+ char cur = current;
+ prepareNext();
+ return Character.valueOf(cur);
+ }
+
+ /**
+ * Always throws UnsupportedOperationException.
+ *
+ * @throws UnsupportedOperationException
+ * @see java.util.Iterator#remove()
+ */
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
}
diff --git a/src/test/java/org/apache/commons/lang3/CharRangeTest.java b/src/test/java/org/apache/commons/lang3/CharRangeTest.java
index 1bc1cc3f2..d84f17167 100644
--- a/src/test/java/org/apache/commons/lang3/CharRangeTest.java
+++ b/src/test/java/org/apache/commons/lang3/CharRangeTest.java
@@ -19,6 +19,8 @@
package org.apache.commons.lang3;
import java.lang.reflect.Modifier;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
import junit.framework.TestCase;
@@ -301,7 +303,73 @@ public class CharRangeTest extends TestCase {
assertEquals("The Range must not be null", e.getMessage());
}
}
-
+
+ public void testIterator() {
+ CharRange a = CharRange.is('a');
+ CharRange ad = CharRange.isIn('a', 'd');
+ CharRange nota = CharRange.isNot('a');
+ CharRange emptySet = CharRange.isNotIn((char) 0, Character.MAX_VALUE);
+ CharRange notFirst = CharRange.isNotIn((char) 1, Character.MAX_VALUE);
+ CharRange notLast = CharRange.isNotIn((char) 0, (char) (Character.MAX_VALUE - 1));
+
+ Iterator aIt = a.iterator();
+ assertNotNull(aIt);
+ assertTrue(aIt.hasNext());
+ assertEquals(Character.valueOf('a'), aIt.next());
+ assertFalse(aIt.hasNext());
+
+ Iterator adIt = ad.iterator();
+ assertNotNull(adIt);
+ assertTrue(adIt.hasNext());
+ assertEquals(Character.valueOf('a'), adIt.next());
+ assertEquals(Character.valueOf('b'), adIt.next());
+ assertEquals(Character.valueOf('c'), adIt.next());
+ assertEquals(Character.valueOf('d'), adIt.next());
+ assertFalse(adIt.hasNext());
+
+ Iterator notaIt = nota.iterator();
+ assertNotNull(notaIt);
+ assertTrue(notaIt.hasNext());
+ while (notaIt.hasNext()) {
+ Character c = (Character) notaIt.next();
+ assertFalse('a' == c.charValue());
+ }
+
+ Iterator emptySetIt = emptySet.iterator();
+ assertNotNull(emptySetIt);
+ assertFalse(emptySetIt.hasNext());
+ try {
+ emptySetIt.next();
+ fail("Should throw NoSuchElementException");
+ } catch (NoSuchElementException e) {
+ assertTrue(true);
+ }
+
+ Iterator notFirstIt = notFirst.iterator();
+ assertNotNull(notFirstIt);
+ assertTrue(notFirstIt.hasNext());
+ assertEquals(Character.valueOf((char) 0), notFirstIt.next());
+ assertFalse(notFirstIt.hasNext());
+ try {
+ notFirstIt.next();
+ fail("Should throw NoSuchElementException");
+ } catch (NoSuchElementException e) {
+ assertTrue(true);
+ }
+
+ Iterator notLastIt = notLast.iterator();
+ assertNotNull(notLastIt);
+ assertTrue(notLastIt.hasNext());
+ assertEquals(Character.valueOf(Character.MAX_VALUE), notLastIt.next());
+ assertFalse(notLastIt.hasNext());
+ try {
+ notLastIt.next();
+ fail("Should throw NoSuchElementException");
+ } catch (NoSuchElementException e) {
+ assertTrue(true);
+ }
+ }
+
//-----------------------------------------------------------------------
public void testSerialization() {
CharRange range = CharRange.is('a');