diff --git a/src/main/java/org/apache/commons/csv/Lexer.java b/src/main/java/org/apache/commons/csv/Lexer.java index 1711322792..80bde6c7e8 100644 --- a/src/main/java/org/apache/commons/csv/Lexer.java +++ b/src/main/java/org/apache/commons/csv/Lexer.java @@ -334,18 +334,7 @@ private Token parseEncapsulatedToken(final Token token) throws IOException { while (true) { c = reader.read(); - if (isEscape(c)) { - if (isEscapeDelimiter()) { - token.content.append(delimiter); - } else { - final int unescaped = readEscape(); - if (unescaped == EOF) { // unexpected char after escape - token.content.append((char) c).append((char) reader.getLastChar()); - } else { - token.content.append((char) unescaped); - } - } - } else if (isQuoteChar(c)) { + if (isQuoteChar(c)) { if (isQuoteChar(reader.lookAhead())) { // double or escaped encapsulator -> add single encapsulator to token c = reader.read(); @@ -376,6 +365,17 @@ private Token parseEncapsulatedToken(final Token token) throws IOException { } } } + } else if (isEscape(c)) { + if (isEscapeDelimiter()) { + token.content.append(delimiter); + } else { + final int unescaped = readEscape(); + if (unescaped == EOF) { // unexpected char after escape + token.content.append((char) c).append((char) reader.getLastChar()); + } else { + token.content.append((char) unescaped); + } + } } else if (isEndOfFile(c)) { if (lenientEof) { token.type = Token.Type.EOF; diff --git a/src/test/java/org/apache/commons/csv/CSVParserTest.java b/src/test/java/org/apache/commons/csv/CSVParserTest.java index b3a513780f..fd9de361af 100644 --- a/src/test/java/org/apache/commons/csv/CSVParserTest.java +++ b/src/test/java/org/apache/commons/csv/CSVParserTest.java @@ -1562,6 +1562,41 @@ public void testTrim() throws Exception { assertEquals(3, record.size()); }} + @Test + public void testParsingPrintedEmptyFirstColumn() throws Exception { + String[][] lines = new String[][] { + {"a", "b"}, + {"", "x"} + }; + Exception firstException = null; + for (CSVFormat.Predefined format : CSVFormat.Predefined.values()) { + try { + StringWriter buf = new StringWriter(); + try (CSVPrinter printer = new CSVPrinter(buf, format.getFormat())) { + for (String[] line : lines) { + printer.printRecord((Object[]) line); + } + } + try (CSVParser csvRecords = new CSVParser(new StringReader(buf.toString()), format.getFormat())) { + for (String[] line : lines) { + assertArrayEquals(line, csvRecords.nextRecord().values()); + } + assertNull(csvRecords.nextRecord()); + } + } catch (Exception | Error e) { + Exception detailedException = new RuntimeException("format: " + format, e); + if (firstException == null) { + firstException = detailedException; + } else { + firstException.addSuppressed(detailedException); + } + } + } + + if (firstException != null) + throw firstException; + } + private void validateLineNumbers(final String lineSeparator) throws IOException { try (final CSVParser parser = CSVParser.parse("a" + lineSeparator + "b" + lineSeparator + "c", CSVFormat.DEFAULT.withRecordSeparator(lineSeparator))) { assertEquals(0, parser.getCurrentLineNumber());