带有字符串分隔符的Java CSV解析器(多字符)

时间:2011-12-28 09:00:18

标签: java csv delimiter separator

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

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

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

如果有一个本地支持字符串分隔符的库,那将是很好的,因此不需要预处理。这意味着CSV现在标记为“CharSequence-Separated Values”数据。 : - )

3 个答案:

答案 0 :(得分:4)

这是一个很好的问题。在我查看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 String tokenizer方法。

    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. 使用“字段忽略”方法来解析经过验证的数据,确保已经指定了正确数量的字段。
  3. 编写自己的CSV解析器效率不高,但可能更容易: - )

答案 1 :(得分:0)

尝试opencsv

它可以完成您需要的一切,包括(尤其是)在引用值内处理嵌入式分隔符(例如"a,b", "c"解析为["a,b", "c"]

我已成功使用它,我喜欢它。

编辑:

由于opencsv只处理单字符分隔符,因此可以解决这个问题:

String input;
char someCharNotInInput = '|';
String delimiter = "abc"; // or whatever
input.replaceAll(delimiter, someCharNotInInput);
new CSVReader(input, someCharNotInInput); // etc
// Put it back into each value read
value.replaceAll(someCharNotInInput, delimiter); // in case it's inside delimiters

答案 2 :(得分:0)

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

我知道速度很慢,但是我选择了Scanner。它具有许多功能,并且可以将任何想要的字符串用作记录定界符来滚动自己的简单CSV阅读器。它还可以让您解析非常大的CSV文件(之前我已经完成了10GB的单个文件),因为您一次只能读取一个记录。

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

我希望有一个更快的解决方案,但是我发现没有库支持它。自2017年初以来,FasterXML已公开添加此功能:https://github.com/FasterXML/jackson-dataformats-text/issues/14