【问题标题】:Tokenize CSV line escape double quotes标记 CSV 行转义双引号
【发布时间】:2020-02-21 22:46:57
【问题描述】:

我有一个逗号分隔的 CSV 行:

1000102257,b,N,159999,3,4545656,4,,,,"6,125% NORDRHEIN-WESTF.LA.SCHA.R.239 21.12. "18"

包含逗号分隔符(,)作为内容的标记被双引号以将其转义。

如您所见,最后一个标记被隔离在双引号之间,但出现了另一个双引号 ("18),这破坏了标记化机制:

"6,125% NORDRHEIN-WESTF.LA.SCHA.R.239 21.12. "18"

这是我将行拆分为标记的代码:

public static void main(String[] args) {
    final String cvsSplitterEscapingQuotes = ",(?=([^\\\"]*\\\"[^\\\"]*\\\")*[^\\\"]*$)";
    String strLine = "1000102257,b,N,159999,3,4545656,4,,,,\"6,125% NORDRHEIN-WESTF.LA.SCHA.R.239 21.12. \"18\"";
    String[] tokens = strLine.split(cvsSplitterEscapingQuotes, -1);
}

如何转义引号内的中间双引号?

【问题讨论】:

    标签: java regex csv


    【解决方案1】:

    不要自己解析 CSV,使用库。即使像 CSV 这样简单的格式也有细微差别:字段可以用引号转义或不转义,文件可以有或没有标题等等。除此之外,您还必须测试和维护您编写的代码。所以少写代码,重用库是好事。

    Java 中有很多 CSV 库:

    恕我直言,前两个是最受欢迎的。

    这是 Apache Commons CSV 的示例:

    final Reader in = new FileReader("counties.csv");
    final Iterable<CSVRecord> records = CSVFormat.DEFAULT.parse(in);
    
    for (final CSVRecord record : records) { // Simply iterate over the records via foreach loop. All the parsing is handler for you
        String populationString = record.get(7); // Indexes are zero-based
        String populationString = record.get("population"); // Or, if your file has headers, you can just use them
    
        … // Do whatever you want with the population
    }
    

    看看它是多么容易!并且它将与其他解析器类似。

    【讨论】:

      【解决方案2】:

      忽略不跟在逗号或换行符后面的双引号

      【讨论】:

        【解决方案3】:

        这个未转义的正则表达式,经过测试here

        (".*"|[^,"]+|(?<=,)(?=,))
        

        用逗号分割你的字符串,但没有引号。以下是它的工作原理:

        (                          // Start the match
         ".*"                      // Greedily match anything in quotes
             |[^,"]+               // Or, greedily match anything that isn't a comma or quote
                    |(?<=,)(?=,)   // Or, look behind for a comma and ahead for a comma
                                   //    (the empty match)
                                )  // End match.
        

        当然,这不会匹配逗号分隔字符串开头或结尾的空字段,但您可以添加一个额外的位:

        |^(?=,)           // At the beginning, look forward for a comma
               |(?<=,)$   // Look back for a comma, and at the end
        

        所以整个模式是:

        (".*"|[^,"]+|(?<=,)(?=,))|^(?=,)|(?<=,)$
        

        但正如@madhead 所说,除非这是家庭作业,否则请使用图书馆!

        【讨论】:

        • 谢谢。您的解决方案有效,但正如 @madhead 建议我的那样,我选择了一个库。
        猜你喜欢
        • 1970-01-01
        • 2013-07-22
        • 1970-01-01
        • 2020-11-26
        • 1970-01-01
        • 2013-06-17
        • 1970-01-01
        • 2013-08-09
        • 1970-01-01
        相关资源
        最近更新 更多