带字符串分隔符的 Java CSV 解析器(多字符)忽略隐式中介字段自己卷更新

2022-09-02 22:37:47

是否有任何Java开源库支持CSV的多字符(即长度为>1的字符串)分隔符(分隔符)?

根据定义,CSV = 逗号分隔值数据,其中单个字符 (',') 作为分隔符。但是,还存在许多其他单字符替代项(例如,制表符),使CSV代表“字符分隔值”数据(本质上是DSV:分隔符分隔值数据)。

用于CSV的主要Java开源库(例如OpenCSV)几乎支持任何字符作为分隔符,但不支持字符串(多字符)分隔符。因此,对于用“|||”等字符串分隔的数据,除了预处理输入以将字符串转换为单字符分隔符之外,没有其他选择。从那时起,数据可以解析为单字符分隔值。

因此,如果有一个本机支持字符串分隔符的库,那就太好了,这样就不需要预处理了。这意味着CSV现在代表“字符序列分隔值”数据。:-)


答案 1

这是一个好问题。这个问题对我来说并不明显,直到我查看了javadocs并意识到opencsv仅支持字符作为分隔符,而不是字符串。

这里有一些建议的解决方法(Groovy中的示例可以转换为java)。

忽略隐式中介字段

继续使用 OpenCSV,但忽略空字段。显然,这是一个作弊,但它可以很好地解析行为良好的数据。

    CSVParser csv = new CSVParser((char)'|')

    String[] result = csv.parseLine('J||Project report||"F, G, I"||1')

    assert result[0] == "J"
    assert result[2] == "Project report"
    assert result[4] == "F, G, I"
    assert result[6] == "1"

    CSVParser csv = new CSVParser((char)'|')

    String[] result = csv.parseLine('J|||Project report|||"F, G, I"|||1')

    assert result[0] == "J"
    assert result[3] == "Project report"
    assert result[6] == "F, G, I"
    assert result[9] == "1"

自己卷

使用 Java 字符串分词器方法。

    def result = 'J|||Project report|||"F, G, I"|||1'.tokenize('|||')

    assert result[0] == "J"
    assert result[1] == "Project report"
    assert result[2] == "\"F, G, I\""
    assert result[3] == "1"

此方法的缺点是您失去了忽略引号字符或转义分隔符的能力。

更新

与其预先处理数据,改变其内容,为什么不将上述两种方法组合成两个步骤:

  1. 使用“滚动自己的”首先验证数据。拆分每行并证明它包含请求的字段数。
  2. 使用“字段忽略”方法来解析经过验证的数据,确保已指定正确数量的字段。

不是很高效,但可能比编写自己的CSV解析器更容易:-)


答案 2

这些解决方案都不适合我,因为它们都假设您可以将整个CSV文件存储在内存中,从而可以轻松执行键入操作。replaceAll

我知道它很慢,但我去了.它具有惊人的功能,并且可以使用您想要的任何字符串作为记录分隔符滚动自己的简单CSV阅读器。它还允许您解析非常大的CSV文件(我以前做过10GB的单个文件),因为您可以一次读取一个记录。Scanner

Scanner s = new Scanner(inputStream, "UTF-8").useDelimiter(">|\n");

我更喜欢更快的解决方案,但我找到的库都不支持它。自2017年初以来,FasterXML一直有一个开放的票来添加这种功能:https://github.com/FasterXML/jackson-dataformats-text/issues/14