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
This commit is contained in:
Emmanuel Bourg 2011-11-09 23:04:13 +00:00
parent a7bd28c496
commit 045dbbbe4a
2 changed files with 100 additions and 9 deletions

View File

@ -20,7 +20,9 @@ package org.apache.commons.csv;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.NoSuchElementException;
import static org.apache.commons.csv.CSVParser.Token.Type.*; import static org.apache.commons.csv.CSVParser.Token.Type.*;
@ -33,14 +35,18 @@ import static org.apache.commons.csv.CSVParser.Token.Type.*;
* <p>Parsing of a csv-string having tabs as separators, * <p>Parsing of a csv-string having tabs as separators,
* '"' as an optional value encapsulator, and comments starting with '#':</p> * '"' as an optional value encapsulator, and comments starting with '#':</p>
* <pre> * <pre>
* String[][] record = * CSVFormat format = new CSVFormat('\t', '"', '#');
* (new CSVParser(new StringReader("a\tb\nc\td"), new CSVFormat('\t','"','#'))).getAllValues(); * Reader in = new StringReader("a\tb\nc\td");
* String[][] records = new CSVParser(in, format).getRecords();
* </pre> * </pre>
* *
* <p>Parsing of a csv-string in Excel CSV format</p> * <p>Parsing of a csv-string in Excel CSV format, using a for-each loop:</p>
* <pre> * <pre>
* String[][] record = * Reader in = new StringReader("a;b\nc;d");
* (new CSVParser(new StringReader("a;b\nc;d"), CSVFormat.EXCEL)).getAllValues(); * CSVParser parser = new CSVParser(in, CSVFormat.EXCEL);
* for (String[] record : parser) {
* ...
* }
* </pre> * </pre>
* *
* <p> * <p>
@ -50,7 +56,7 @@ import static org.apache.commons.csv.CSVParser.Token.Type.*;
* <p>see <a href="package-summary.html">package documentation</a> * <p>see <a href="package-summary.html">package documentation</a>
* for more details</p> * for more details</p>
*/ */
public class CSVParser { public class CSVParser implements Iterable<String[]> {
/** length of the initial token (content-)buffer */ /** length of the initial token (content-)buffer */
private static final int INITIAL_TOKEN_LENGTH = 50; private static final int INITIAL_TOKEN_LENGTH = 50;
@ -172,7 +178,7 @@ public class CSVParser {
* ('null' when end of file has been reached) * ('null' when end of file has been reached)
* @throws IOException on parse error or input read-failure * @throws IOException on parse error or input read-failure
*/ */
public String[] getLine() throws IOException { String[] getLine() throws IOException {
String[] ret = EMPTY_STRING_ARRAY; String[] ret = EMPTY_STRING_ARRAY;
record.clear(); record.clear();
while (true) { while (true) {
@ -208,6 +214,49 @@ public class CSVParser {
return ret; return ret;
} }
/**
* Returns an iterator on the records. IOExceptions occuring
* during the iteration are wrapped in a RuntimeException.
*/
public Iterator<String[]> iterator() {
return new Iterator<String[]>() {
String[] current;
public boolean hasNext() {
if (current == null) {
current = getNextLine();
}
return current != null;
}
public String[] next() {
String[] next = current;
current = null;
if (next == null) {
// hasNext() wasn't called before
next = getNextLine();
if (next == null) {
throw new NoSuchElementException("No more CSV records available");
}
}
return next;
}
private String[] getNextLine() {
try {
return getLine();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void remove() { }
};
}
/** /**
* Returns the current line number in the input stream. * Returns the current line number in the input stream.
* <p/> * <p/>

View File

@ -20,7 +20,11 @@ package org.apache.commons.csv;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.io.StringReader; import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import junit.framework.TestCase; import junit.framework.TestCase;
@ -219,7 +223,7 @@ public class CSVParserTest extends TestCase {
assertTrue(parser.getLine() == null); assertTrue(parser.getLine() == null);
} }
public void testGetAllValues() throws IOException { public void testGetRecords() throws IOException {
CSVParser parser = new CSVParser(new StringReader(code)); CSVParser parser = new CSVParser(new StringReader(code));
String[][] tmp = parser.getRecords(); String[][] tmp = parser.getRecords();
assertEquals(res.length, tmp.length); assertEquals(res.length, tmp.length);
@ -518,7 +522,7 @@ public class CSVParserTest extends TestCase {
public void testUnicodeEscape() throws IOException { public void testUnicodeEscape() throws IOException {
String code = "abc,\\u0070\\u0075\\u0062\\u006C\\u0069\\u0063"; String code = "abc,\\u0070\\u0075\\u0062\\u006C\\u0069\\u0063";
CSVParser parser = new CSVParser(new StringReader(code), CSVFormat.DEFAULT.withUnicodeEscapesInterpreted(true)); CSVParser parser = new CSVParser(new StringReader(code), CSVFormat.DEFAULT.withUnicodeEscapesInterpreted(true));
String[] data = parser.getLine(); String[] data = parser.iterator().next();
assertEquals(2, data.length); assertEquals(2, data.length);
assertEquals("abc", data[0]); assertEquals("abc", data[0]);
assertEquals("public", data[1]); assertEquals("public", data[1]);
@ -565,4 +569,42 @@ public class CSVParserTest extends TestCase {
assertEquals(TOKEN + ";five;", parser.testNextToken()); assertEquals(TOKEN + ";five;", parser.testNextToken());
assertEquals(EOF + ";six;", parser.testNextToken()); assertEquals(EOF + ";six;", parser.testNextToken());
} }
public void testForEach() {
List<String[]> records = new ArrayList<String[]>();
String code = "a,b,c\n1,2,3\nx,y,z";
Reader in = new StringReader(code);
for (String[] record : new CSVParser(in)) {
records.add(record);
}
assertEquals(3, records.size());
assertTrue(Arrays.equals(new String[] {"a", "b", "c"}, records.get(0)));
assertTrue(Arrays.equals(new String[]{"1", "2", "3"}, records.get(1)));
assertTrue(Arrays.equals(new String[] {"x", "y", "z"}, records.get(2)));
}
public void testIterator() {
String code = "a,b,c\n1,2,3\nx,y,z";
Iterator<String[]> iterator = new CSVParser(new StringReader(code)).iterator();
assertTrue(iterator.hasNext());
iterator.remove();
assertTrue(Arrays.equals(new String[]{"a", "b", "c"}, iterator.next()));
assertTrue(Arrays.equals(new String[]{"1", "2", "3"}, iterator.next()));
assertTrue(iterator.hasNext());
assertTrue(iterator.hasNext());
assertTrue(iterator.hasNext());
assertTrue(Arrays.equals(new String[]{"x", "y", "z"}, iterator.next()));
assertFalse(iterator.hasNext());
try {
iterator.next();
fail("NoSuchElementException expected");
} catch (NoSuchElementException e) {
// expected
}
}
} }