如何解析可能有两种分隔符的CSV文件?

14

就我的情况而言,有效的 CSV 文件是用逗号或分号分隔的。我可以尝试其他库,但必须使用 Java。阅读 Apache CSVParser API 后,我能想到的唯一办法似乎是做这个看起来既低效又丑陋的事情。

try
{
   BufferedReader reader = new BufferedReader(new InputStreamReader(file));
   CSVFormat csvFormat = CSVFormat.EXCEL.withHeader().withDelimiter(';');
   CSVParser parser = csvFormat.parse( reader );
   // now read the records
} 
catch (IOException eee) 
{
   try
   {
      // try the other valid delimeter
      csvFormat = CSVFormat.EXCEL.withHeader().withDelimiter(',');
      parser = csvFormat.parse( reader );
      // now read the records
   }
   catch (IOException eee) 
   {
      // then its really not a valid CSV file
   }
}

有没有办法先检查分隔符,或者允许两个分隔符?有没有比捕获异常更好的方法?


我认为你的代码是最好的。在普通CSV文件中没有检测分隔符的方法。唯一检测分隔符的方法是使用多个分隔符进行重试。 - gilchris
只是一个想法,如果您有格式良好的 CSV 文件,您是否可以为其中一个选项执行模式匹配?如果每个字段都用引号括起来,然后用逗号分隔,您可能会发现多个模式 "," 的实例。 - Ryan E
3个回答

8
我们在 uniVocity-parsers中提供了对此的支持。
public static void main(String... args) {
    CsvParserSettings settings = new CsvParserSettings();
    settings.setDelimiterDetectionEnabled(true);

    CsvParser parser = new CsvParser(settings);

    List<String[]> rows = parser.parseAll(file);

}

解析器有很多其他功能,我相信你会发现它们很有用。试试看吧。
免责声明:本库的作者是我,它是开源和免费的(Apache 2.0许可证)。

很棒的解析器,省了我很多麻烦。感谢分享! - Buffalo
很高兴能够帮助!如果您觉得这对您有用,请考虑点赞并回答问题。谢谢! - Jeronimo Backes
我已经在各种奇怪的CSV上测试了解析器,一切顺利。我尝试使用一个简单的"\r\n"分隔文件,甚至在标题之后粘合了前2-3行.. :( 自动检测/提供行分隔符没有任何区别。 - Buffalo
@Buffalo,你介意提供一下你用来测试的文件吗? - Jeronimo Backes
我在这里单独提出了一个问题:https://stackoverflow.com/questions/44208137/handling-r-n-csv-with-univocity - Buffalo
太棒了!你为我节省了很多时间! - Mukhamedali Zhadigerov

0
以下是我解决这个问题的方法:
    private static final Character[] DELIMITERS = {';', ','};
    private static final char NO_DELIMITER = '\0'; //empty char

    private char detectDelimiter() throws IOException {
        try (
            final var reader = new BufferedReader(new InputStreamReader(resource.getInputStream()));
        ) {
            String line = reader.readLine();

            return Arrays.stream(DELIMITERS)
                .filter(s -> line.contains(s.toString()))
                .findFirst()
                .orElse(NO_DELIMITER);
        }
    }

使用示例:

private CSVParser openCsv() throws IOException {

        final var csvFormat = CSVFormat.DEFAULT
            .withFirstRecordAsHeader()
            .withDelimiter(detectDelimiter())
            .withTrim();

        return new CSVParser(new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8), csvFormat);
    }

0

我曾经遇到过同样的问题,我是这样解决的:

    BufferedReader in = Files.newBufferedReader(Paths.get(fileName));
    in.mark(1024);
    String line = in.readLine();
    CSVFormat fileFormat;
    
    if(line.indexOf(';') != -1)
        fileFormat = CSVFormat.EXCEL.withDelimiter(';');
    else
        fileFormat = CSVFormat.EXCEL;
    
    in.reset();

之后您可以使用CSVParser对其进行解析。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接