Skip to content

Commit 045dbbb

Browse files
committed
Made CSVParser iterable to simplify the iteration over the records
git-svn-id: https://svn.apache.org/repos/asf/commons/sandbox/csv/trunk@1200024 13f79535-47bb-0310-9956-ffa450edef68
1 parent a7bd28c commit 045dbbb

2 files changed

Lines changed: 100 additions & 9 deletions

File tree

src/main/java/org/apache/commons/csv/CSVParser.java

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
import java.io.IOException;
2121
import java.io.Reader;
2222
import java.util.ArrayList;
23+
import java.util.Iterator;
2324
import java.util.List;
25+
import java.util.NoSuchElementException;
2426

2527
import static org.apache.commons.csv.CSVParser.Token.Type.*;
2628

@@ -33,14 +35,18 @@
3335
* <p>Parsing of a csv-string having tabs as separators,
3436
* '"' as an optional value encapsulator, and comments starting with '#':</p>
3537
* <pre>
36-
* String[][] record =
37-
* (new CSVParser(new StringReader("a\tb\nc\td"), new CSVFormat('\t','"','#'))).getAllValues();
38+
* CSVFormat format = new CSVFormat('\t', '"', '#');
39+
* Reader in = new StringReader("a\tb\nc\td");
40+
* String[][] records = new CSVParser(in, format).getRecords();
3841
* </pre>
3942
*
40-
* <p>Parsing of a csv-string in Excel CSV format</p>
43+
* <p>Parsing of a csv-string in Excel CSV format, using a for-each loop:</p>
4144
* <pre>
42-
* String[][] record =
43-
* (new CSVParser(new StringReader("a;b\nc;d"), CSVFormat.EXCEL)).getAllValues();
45+
* Reader in = new StringReader("a;b\nc;d");
46+
* CSVParser parser = new CSVParser(in, CSVFormat.EXCEL);
47+
* for (String[] record : parser) {
48+
* ...
49+
* }
4450
* </pre>
4551
*
4652
* <p>
@@ -50,7 +56,7 @@
5056
* <p>see <a href="package-summary.html">package documentation</a>
5157
* for more details</p>
5258
*/
53-
public class CSVParser {
59+
public class CSVParser implements Iterable<String[]> {
5460

5561
/** length of the initial token (content-)buffer */
5662
private static final int INITIAL_TOKEN_LENGTH = 50;
@@ -172,7 +178,7 @@ public String[][] getRecords() throws IOException {
172178
* ('null' when end of file has been reached)
173179
* @throws IOException on parse error or input read-failure
174180
*/
175-
public String[] getLine() throws IOException {
181+
String[] getLine() throws IOException {
176182
String[] ret = EMPTY_STRING_ARRAY;
177183
record.clear();
178184
while (true) {
@@ -208,6 +214,49 @@ public String[] getLine() throws IOException {
208214
return ret;
209215
}
210216

217+
/**
218+
* Returns an iterator on the records. IOExceptions occuring
219+
* during the iteration are wrapped in a RuntimeException.
220+
*/
221+
public Iterator<String[]> iterator() {
222+
return new Iterator<String[]>() {
223+
String[] current;
224+
225+
public boolean hasNext() {
226+
if (current == null) {
227+
current = getNextLine();
228+
}
229+
230+
return current != null;
231+
}
232+
233+
public String[] next() {
234+
String[] next = current;
235+
current = null;
236+
237+
if (next == null) {
238+
// hasNext() wasn't called before
239+
next = getNextLine();
240+
if (next == null) {
241+
throw new NoSuchElementException("No more CSV records available");
242+
}
243+
}
244+
245+
return next;
246+
}
247+
248+
private String[] getNextLine() {
249+
try {
250+
return getLine();
251+
} catch (IOException e) {
252+
throw new RuntimeException(e);
253+
}
254+
}
255+
256+
public void remove() { }
257+
};
258+
}
259+
211260
/**
212261
* Returns the current line number in the input stream.
213262
* <p/>

src/test/java/org/apache/commons/csv/CSVParserTest.java

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@
2020
import java.io.IOException;
2121
import java.io.Reader;
2222
import java.io.StringReader;
23+
import java.util.ArrayList;
2324
import java.util.Arrays;
25+
import java.util.Iterator;
26+
import java.util.List;
27+
import java.util.NoSuchElementException;
2428

2529
import junit.framework.TestCase;
2630

@@ -219,7 +223,7 @@ public void testGetLine() throws IOException {
219223
assertTrue(parser.getLine() == null);
220224
}
221225

222-
public void testGetAllValues() throws IOException {
226+
public void testGetRecords() throws IOException {
223227
CSVParser parser = new CSVParser(new StringReader(code));
224228
String[][] tmp = parser.getRecords();
225229
assertEquals(res.length, tmp.length);
@@ -518,7 +522,7 @@ public void testDefaultFormat() throws IOException {
518522
public void testUnicodeEscape() throws IOException {
519523
String code = "abc,\\u0070\\u0075\\u0062\\u006C\\u0069\\u0063";
520524
CSVParser parser = new CSVParser(new StringReader(code), CSVFormat.DEFAULT.withUnicodeEscapesInterpreted(true));
521-
String[] data = parser.getLine();
525+
String[] data = parser.iterator().next();
522526
assertEquals(2, data.length);
523527
assertEquals("abc", data[0]);
524528
assertEquals("public", data[1]);
@@ -565,4 +569,42 @@ public void testDelimiterIsWhitespace() throws IOException {
565569
assertEquals(TOKEN + ";five;", parser.testNextToken());
566570
assertEquals(EOF + ";six;", parser.testNextToken());
567571
}
572+
573+
public void testForEach() {
574+
List<String[]> records = new ArrayList<String[]>();
575+
576+
String code = "a,b,c\n1,2,3\nx,y,z";
577+
Reader in = new StringReader(code);
578+
579+
for (String[] record : new CSVParser(in)) {
580+
records.add(record);
581+
}
582+
583+
assertEquals(3, records.size());
584+
assertTrue(Arrays.equals(new String[] {"a", "b", "c"}, records.get(0)));
585+
assertTrue(Arrays.equals(new String[]{"1", "2", "3"}, records.get(1)));
586+
assertTrue(Arrays.equals(new String[] {"x", "y", "z"}, records.get(2)));
587+
}
588+
589+
public void testIterator() {
590+
String code = "a,b,c\n1,2,3\nx,y,z";
591+
Iterator<String[]> iterator = new CSVParser(new StringReader(code)).iterator();
592+
593+
assertTrue(iterator.hasNext());
594+
iterator.remove();
595+
assertTrue(Arrays.equals(new String[]{"a", "b", "c"}, iterator.next()));
596+
assertTrue(Arrays.equals(new String[]{"1", "2", "3"}, iterator.next()));
597+
assertTrue(iterator.hasNext());
598+
assertTrue(iterator.hasNext());
599+
assertTrue(iterator.hasNext());
600+
assertTrue(Arrays.equals(new String[]{"x", "y", "z"}, iterator.next()));
601+
assertFalse(iterator.hasNext());
602+
603+
try {
604+
iterator.next();
605+
fail("NoSuchElementException expected");
606+
} catch (NoSuchElementException e) {
607+
// expected
608+
}
609+
}
568610
}

0 commit comments

Comments
 (0)