【问题标题】:How to parse a comma separated line (CSV) with some items in quotation marks?如何用引号中的某些项目解析逗号分隔行(CSV)?
【发布时间】:2015-12-24 13:20:12
【问题描述】:

我正在尝试使用以下方法解析逗号分隔的字符串:

val array = input.split(",")

然后我注意到一些输入行在引号内有“,”:

data0, "data1", data2, data3, "data4-1, data4-2, data4-3", data5

*注意数据不是很干净,所以有些字段在引号内,有些则不在


我如何将这样的行分成:

array(0) = data0
array(1) = data1
array(2) = data2
array(3) = data3
array(4) = data4-1, data4-2, data4-3
array(5) = data5

【问题讨论】:

  • 解析 CSV 文件可能是出了名的棘手,因为它在引号周围的行为,以及引号中包含的逗号和引号。我建议引入一个以稳健地处理所有边缘情况而著称的库。您可以考虑的选项包括scala-csvtraversable-csv。或者使用像 opencsv 这样的 Java 库。
  • 否则,如果您不想或不能使用库,您可以查看this SO answerthis SO answer 以了解其他人如何处理滚动您自己的 CSV 解析器。
  • @Shadowlands 您能否在答案中总结您的 cmets(因为我认为您已经展示了许多有价值的方法,其他人可以从中受益。)谢谢。
  • @MartinSenne 当然,很高兴将其作为答案(尽管我没有更多要补充的内容)。

标签: java regex scala csv


【解决方案1】:

根据我的cmets:

解析 CSV 文件可能是出了名的棘手,因为它围绕引号的行为,以及引号中包含的逗号和引号。我建议引入一个以稳健地处理所有边缘情况而著称的库。

您可以考虑的选项包括scala-csvtraversable-csv。或者使用像opencsv 这样的Java 库。

否则,如果您不想或不能使用库,您可以查看 this SO answerthis SO answer 以了解其他人如何处理自己滚动的 CSV 解析器。

【讨论】:

  • 感谢暗影国度!如果可能的话,我想使用图书馆。我在这里遇到的一个问题是,我将获得需要解析的“csv 行”,而不是“一个 csv 文件”。有没有可以解析一行而不是整个文件的库?谢谢!
【解决方案2】:

您实际上可以使用正则表达式拆分该行。

val s = """data0, "data1", data2, data3, "data4-1, data4-2, data4-3", data5"""

"""((".*?")|('.*?')|[^"',]+)+""".r.findAllIn(s).foreach(println)

顺便说一句。任何可以解析 csv 文件的库也可以解析单个 csv 行。只需将字符串包装到 StringReader 中即可。

【讨论】:

  • 谢谢!您能否详细说明“任何可以解析 csv 文件的库也可以解析单个 csv 行”。例如,如何修改以下文件解析器以解析单个 csv 行? CSVReader reader = new CSVReader(new FileReader("yourfile.csv"));
  • 应该像这样工作CSVReader reader = new CSVReader(new StringReader("data1,data2,data3"))
【解决方案3】:

我建议使用 CSV 库来解析 CSV 数据 - 格式很混乱,而且很难正确处理。

我建议kantan.csv,主要是因为我是作者,但也因为它让您比将 CSV 流转换为字符串数组列表更进一步。以以下输入为例:

1,Foo,2.0
2,Bar,false

使用kantan.csv,你可以写:

import kantan.csv.ops._

new File("path/to/csv").asUnsafeCsvRows[(Int, String, Either[Float, Boolean])](',', false)

在结果上调用toList 将产生:

List((1,Foo,Left(2.0)), (2,Bar,Right(false)))

请注意最后一列是浮点数还是布尔值,但这是在迭代器的每个元素的类型中捕获的。

【讨论】:

    【解决方案4】:

    以下是我解析 CSV 行的解决方案:

    String[] res = row.split(";");
    for (int i = 0; i < res.length; i++) {
        res[i] = deQuotes(res[i]);
    }
    return res;
    

    用 REGEXP 删除引号:

    static final Pattern PATTERN_DE_QUOTES = Pattern.compile("(?i)^\\\"(.*)\\\"$");
    
    static String deQuotes(String s) {
        Matcher matcher;
        if ((matcher = PATTERN_DE_QUOTES.matcher(s)).find()) {
            return matcher.group(1).replaceAll("\"\"", "\"");
        }
        return s;
    }
    

    希望对你有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多