【问题标题】:how to solve this error, CSVFormat with double quote using apache commons?如何解决这个错误,CSVFormat with double quote using apache commons?
【发布时间】:2021-05-05 18:20:29
【问题描述】:

我有一个我无法解决的错误,我使用 Apache Commons 读取我的 CSV 文件,但是有一行包含一个带双引号的字符串,它不是分隔符,它是字符串的一部分,我想要一个替代方案来摆脱应用程序给出的错误。这是代码和错误。

Reader in = Files.newBufferedReader(Paths.get(nomeArquivoCorretores),  Charset.forName("ISO-8859-1"));      
Iterable<CSVRecord> records = CSVFormat
                    .newFormat(',')
                    .withQuote('"')
                    .withEscape('\\')
                    .withHeader(cabecalhoCorretores)
                    .withTrailingDelimiter()
                    .withQuoteMode(QuoteMode.ALL)
                    .parse(in);
for (CSVRecord record : records) {
                try { ... }

我在尝试遍历 csv 可迭代列表时遇到此类错误。

java.lang.IllegalStateException: IOException reading next record: java.io.IOException: (line 1) invalid char between encapsulated token and delimiter。

它理解为好像双引号是一个分隔符,但它是字符串的一部分并且正在破坏算法过程

【问题讨论】:

  • 你能edit你的问题并添加示例输入吗?确切的错误信息? (minimal reproducible example 大大增加了你得到答案的机会。)只是猜测:听起来你有一个损坏的 CSV 文件,其中的字段没有转义 properly。如果是这种情况,请与生成该文件的人核实。
  • Robert 我编辑了问题,执行代码时仍然出现错误。
  • 导致错误的输入行是什么?
  • 86954708000105,"LOPES "G" ADMC.CORRETORA DE SEGUROS LTDA",PJ, ,0,Suspenso,,,,

标签: java runtime-error java-11 apache-commons


【解决方案1】:

您输入的 CSV 无效。在第 2 节第 7 项中,RFC 4180 声明:

如果使用双引号将字段括起来,则出现在字段内的双引号必须通过在其前面加上另一个双引号来进行转义。

这里不是这样:

86954708000105,"LOPES "G" ADMC.CORRETORA DE SEGUROS LTDA",PJ, ,0,Suspenso,,,,

应该是

86954708000105,"LOPES ""G"" ADMC.CORRETORA DE SEGUROS LTDA",PJ, ,0,Suspenso,,,,

解决此问题的最佳方法可能是修复生成此无效 CSV 的程序

如果这不可能,您可以尝试解决它,但这将是一个脆弱的 hack。假设有缺陷的 CSV 生成器至少在其缺陷方面是一致的,并且从不在字段中加倍引号,您可以首先将文件作为纯文本读取,尝试修复引号,然后将结果提供给实际的 CSV 阅读器。

import java.io.*;
import org.apache.commons.csv.*;

public class CsvHack {
    public static void main(String[] args) throws Exception {
        String csvdata = "86954708000105,\"LOPES \"G\" ADMC.CORRETORA DE SEGUROS LTDA\",PJ, ,0,Suspenso,,,,";
        BufferedReader reader = new BufferedReader(new StringReader(csvdata));

        StringBuilder buffer = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            line = line.replaceAll("([^,])\"", "$1\"\"");
            line = line.replaceAll("\",", "\"\",");
            buffer.append(line);
            buffer.append("\r\n");
        }
        Reader hack = new StringReader(buffer.toString());

        Iterable<CSVRecord> records = CSVFormat
            .newFormat(',')
            .withQuote('"')
            .withEscape('\\')
            .withTrailingDelimiter()
            .withQuoteMode(QuoteMode.ALL)
            .parse(hack);
        for (CSVRecord record : records) {
            System.out.println(record.get(1));
        }
    }
}

这会将整个文件读入内存中的StringBuilder(如果您正在处理大文件,这可能已经不行了),然后它使用正则表达式替换不在a之后或之前的引号逗号加两个引号。如果引用的文本中有逗号,这将中断;正则表达式是错误的工具。

另一种方法是实现您自己的 java.io.Reader 并将其放在文件和 CSV 解析器之间,然后在该阅读器的 read 方法中修复引号。

如果您得到有效引用的 CSV,这些方法会通过添加额外的引号将其搞砸。

再次,我强烈建议修复输出有缺陷的 CSV 的程序。

【讨论】:

    猜你喜欢
    • 2012-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-30
    • 2020-11-15
    • 2019-10-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多