OpenCSV 可以忽略记录中的尾随逗号吗?

Can OpenCSV ignore trailing commas on records?

像这样的尾随逗号的 CSV:

name, phone
joe, 123-456-7890,
bob, 333-555-6666,

这样处理的:

CSVReaderHeaderAware r = new CSVReaderHeaderAware(reader);
Map<String, String> values = r.readMap();

会抛出这个异常:

java.io.IOException: Error on record number 2: The number of data elements is not the same as the number of header elements

现在我使用 sed 从输入文件中去除逗号:

find . -type f -exec sed -i 's/,*\r*$//' {} \;

是否有一些简单的方法可以告诉 OpenCSV 忽略尾随逗号?

OpenCSV 维护者评论 here。从 OpenCSV v5.1 开始,没有简单的方法可以完成此操作,目前最好使用 sed 等预处理文件。

根据@Andrew 的回答中提供的link,这是格式错误的 CSV 输入。

但是正如自己的维护者所建议的那样(here):

If you know you will always have single-line records, you could derive a class from CSVReader, override getNextLine() to call super.getNextLine(), then cut off the trailing comma, and of course, pass your new reader into opencsv to use in parsing.

换句话说,创建您自己的 CustomCSVReader 并删除最后一个逗号。

这是一个例子:

import com.opencsv.CSVReader;

public class CustomCSVReader extends CSVReader {

public CustomCSVReader(Reader reader) {
    super(reader);
}

@Override
protected String getNextLine() throws IOException {
    String line = super.getNextLine();
    if (line == null) {
        return null;
    }
    
    boolean endsWithComma = line.endsWith(",");
    if (endsWithComma) {
        return line.substring(0, line.length() - 1);
    }
    return line;
}
}

使用 CustomCSVReader 的模型转换器

public class CustomCSVParser{

public List<User> convert(String data) {
    return new CsvToBeanBuilder<Transaction>(new CustomCSVReader(new StringReader(data)))
            .withType(User.class)
            .build()
            .parse();

}

模特class

import com.opencsv.bean.CsvBindByName;

public class User {

@CsvBindByName(column = "name")
private String userName;

@CsvBindByName(column = "phone")
private String phoneNumber;

// Constructor, Getters and Setters ommited
}

测试Class

class CustomCSVParserTest {

private CustomCSVParser instance;

@BeforeEach
void setUp() {
    instance = new CustomCSVParser();
}

@Test
void csvInput_withCommaInLastLine_mustBeParsed() {

    String data = "name, phone
     joe, 123-456-7890,
     bob, 333-555-6666,";


    List<User> result = instance.convert(data);

    List<User> expectedResult = Arrays.asList(
            new User("joe", "123-456-7890"),
            new User("bob", "333-555-6666"));

    Assertions.assertArrayEquals(expectedResult.toArray(), result.toArray());

}
}

就是这样。