Skip to content

Commit daf9849

Browse files
committed
[CSV-52] Keep track of record numbers.
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/csv/trunk@1397895 13f79535-47bb-0310-9956-ffa450edef68
1 parent 3d72cb0 commit daf9849

3 files changed

Lines changed: 92 additions & 24 deletions

File tree

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

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ public class CSVParser implements Iterable<CSVRecord> {
7070

7171
private final Lexer lexer;
7272
private final Map<String, Integer> headerMap;
73+
private long recordNumber;
7374

7475
// the following objects are shared to reduce garbage
7576

@@ -134,14 +135,25 @@ public Map<String, Integer> getHeaderMap() {
134135
/**
135136
* Returns the current line number in the input stream.
136137
* <p/>
137-
* ATTENTION: If your CSV input has multiline-values, the returned number does not correspond to the record-number.
138+
* ATTENTION: If your CSV input has multi-line values, the returned number does not correspond to the record number.
138139
*
139140
* @return current line number
140141
*/
141142
public int getLineNumber() {
142143
return lexer.getLineNumber();
143144
}
144145

146+
/**
147+
* Returns the current record number in the input stream.
148+
* <p/>
149+
* ATTENTION: If your CSV input has multi-line values, the returned number does not correspond to the line number.
150+
*
151+
* @return current line number
152+
*/
153+
public long getRecordNumber() {
154+
return recordNumber;
155+
}
156+
145157
/**
146158
* Parses the next record from the current point in the stream.
147159
*
@@ -150,7 +162,7 @@ public int getLineNumber() {
150162
* on parse error or input read-failure
151163
*/
152164
CSVRecord getRecord() throws IOException {
153-
CSVRecord result = new CSVRecord(null, headerMap, null);
165+
CSVRecord result = new CSVRecord(null, headerMap, null, recordNumber + 1);
154166
record.clear();
155167
StringBuilder sb = null;
156168
do {
@@ -185,8 +197,9 @@ CSVRecord getRecord() throws IOException {
185197
} while (reusableToken.type == TOKEN);
186198

187199
if (!record.isEmpty()) {
200+
recordNumber++;
188201
final String comment = sb == null ? null : sb.toString();
189-
result = new CSVRecord(record.toArray(new String[record.size()]), headerMap, comment);
202+
result = new CSVRecord(record.toArray(new String[record.size()]), headerMap, comment, this.recordNumber);
190203
}
191204
return result;
192205
}

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,12 @@ public class CSVRecord implements Serializable, Iterable<String> {
3939

4040
/** The accumulated comments (if any) */
4141
private final String comment;
42+
43+
/** The record number. */
44+
private final long recordNumber;
4245

43-
CSVRecord(final String[] values, final Map<String, Integer> mapping, final String comment) {
46+
CSVRecord(final String[] values, final Map<String, Integer> mapping, final String comment, long recordNumber) {
47+
this.recordNumber = recordNumber;
4448
this.values = values != null ? values : EMPTY_STRING_ARRAY;
4549
this.mapping = mapping;
4650
this.comment = comment;
@@ -107,6 +111,10 @@ public String getComment() {
107111
return comment;
108112
}
109113

114+
public long getRecordNumber() {
115+
return recordNumber;
116+
}
117+
110118
/**
111119
* Returns the number of values in this record.
112120
*/
@@ -118,4 +126,5 @@ public int size() {
118126
public String toString() {
119127
return Arrays.toString(values);
120128
}
129+
121130
}

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

Lines changed: 66 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package org.apache.commons.csv;
1919

2020
import static org.apache.commons.csv.Constants.CRLF;
21+
import static org.apache.commons.csv.Constants.CR;
2122
import static org.apache.commons.csv.Constants.LF;
2223
import static org.junit.Assert.assertArrayEquals;
2324
import static org.junit.Assert.assertEquals;
@@ -586,43 +587,88 @@ public void testGetHeaderMap() throws Exception {
586587

587588
@Test
588589
public void testGetLineNumberWithLF() throws Exception {
589-
final CSVParser parser = new CSVParser("a\nb\nc", CSVFormat.DEFAULT.withLineSeparator(LF));
590-
591-
assertEquals(0, parser.getLineNumber());
592-
assertNotNull(parser.getRecord());
593-
assertEquals(1, parser.getLineNumber());
594-
assertNotNull(parser.getRecord());
595-
assertEquals(2, parser.getLineNumber());
596-
assertNotNull(parser.getRecord());
597-
assertEquals(2, parser.getLineNumber());
598-
assertNull(parser.getRecord());
590+
validateLineNumbers(String.valueOf(LF));
599591
}
600592

601593
@Test
602594
public void testGetLineNumberWithCRLF() throws Exception {
603-
final CSVParser parser = new CSVParser("a\r\nb\r\nc", CSVFormat.DEFAULT.withLineSeparator(CRLF));
595+
validateLineNumbers(CRLF);
596+
}
597+
598+
@Test
599+
public void testGetLineNumberWithCR() throws Exception {
600+
validateLineNumbers(String.valueOf(CR));
601+
}
602+
603+
@Test
604+
public void testGetRecordNumberWithLF() throws Exception {
605+
validateRecordNumbers(String.valueOf(LF));
606+
}
604607

608+
@Test
609+
public void testGetRecordWithMultiiLineValues() throws Exception {
610+
final CSVParser parser = new CSVParser("\"a\r\n1\",\"a\r\n2\"" + CRLF + "\"b\r\n1\",\"b\r\n2\"" + CRLF + "\"c\r\n1\",\"c\r\n2\"",
611+
CSVFormat.DEFAULT.withLineSeparator(CRLF));
612+
CSVRecord record;
613+
assertEquals(0, parser.getRecordNumber());
605614
assertEquals(0, parser.getLineNumber());
606-
assertNotNull(parser.getRecord());
607-
assertEquals(1, parser.getLineNumber());
608-
assertNotNull(parser.getRecord());
609-
assertEquals(2, parser.getLineNumber());
610-
assertNotNull(parser.getRecord());
611-
assertEquals(2, parser.getLineNumber());
612-
assertNull(parser.getRecord());
615+
assertNotNull(record = parser.getRecord());
616+
assertEquals(3, parser.getLineNumber());
617+
assertEquals(1, record.getRecordNumber());
618+
assertEquals(1, parser.getRecordNumber());
619+
assertNotNull(record = parser.getRecord());
620+
assertEquals(6, parser.getLineNumber());
621+
assertEquals(2, record.getRecordNumber());
622+
assertEquals(2, parser.getRecordNumber());
623+
assertNotNull(record = parser.getRecord());
624+
assertEquals(8, parser.getLineNumber());
625+
assertEquals(3, record.getRecordNumber());
626+
assertEquals(3, parser.getRecordNumber());
627+
assertNull(record = parser.getRecord());
628+
assertEquals(8, parser.getLineNumber());
629+
assertEquals(3, parser.getRecordNumber());
613630
}
614631

615632
@Test
616-
public void testGetLineNumberWithCR() throws Exception {
617-
final CSVParser parser = new CSVParser("a\rb\rc", CSVFormat.DEFAULT.withLineSeparator("\r"));
633+
public void testGetRecordNumberWithCRLF() throws Exception {
634+
validateRecordNumbers(CRLF);
635+
}
636+
637+
@Test
638+
public void testGetRecordNumberWithCR() throws Exception {
639+
validateRecordNumbers(String.valueOf(CR));
640+
}
618641

642+
private void validateRecordNumbers(String lineSeparator) throws IOException {
643+
final CSVParser parser = new CSVParser("a" + lineSeparator + "b" + lineSeparator + "c", CSVFormat.DEFAULT.withLineSeparator(lineSeparator));
644+
CSVRecord record;
645+
assertEquals(0, parser.getRecordNumber());
646+
assertNotNull(record = parser.getRecord());
647+
assertEquals(1, record.getRecordNumber());
648+
assertEquals(1, parser.getRecordNumber());
649+
assertNotNull(record = parser.getRecord());
650+
assertEquals(2, record.getRecordNumber());
651+
assertEquals(2, parser.getRecordNumber());
652+
assertNotNull(record = parser.getRecord());
653+
assertEquals(3, record.getRecordNumber());
654+
assertEquals(3, parser.getRecordNumber());
655+
assertNull(record = parser.getRecord());
656+
assertEquals(3, parser.getRecordNumber());
657+
}
658+
659+
private void validateLineNumbers(String lineSeparator) throws IOException {
660+
final CSVParser parser = new CSVParser("a" + lineSeparator + "b" + lineSeparator + "c", CSVFormat.DEFAULT.withLineSeparator(lineSeparator));
619661
assertEquals(0, parser.getLineNumber());
620662
assertNotNull(parser.getRecord());
621663
assertEquals(1, parser.getLineNumber());
622664
assertNotNull(parser.getRecord());
623665
assertEquals(2, parser.getLineNumber());
624666
assertNotNull(parser.getRecord());
667+
// Still 2 because the last line is does not have EOL chars
625668
assertEquals(2, parser.getLineNumber());
626669
assertNull(parser.getRecord());
670+
// Still 2 because the last line is does not have EOL chars
671+
assertEquals(2, parser.getLineNumber());
627672
}
673+
628674
}

0 commit comments

Comments
 (0)