正则表达式在csv中找到缺少的双引号

时间:2014-06-11 19:17:11

标签: java regex csv

我们正在处理包含非封闭双引号条目的行的csv文件。这些炸毁了csv解析器,所以我试图整理一个正则表达式来识别这些行,这样我们就可以在尝试处理它们之前将它们从文件中删除。

在下面的示例中,csv解析器到达第2行并包含第3行中第一个双引号之前的所有内容,然后尝试关闭令牌然后因为“关闭”之后有非空白字符而爆炸在下一个逗号之前加双引号。

  

示例第1行,一些数据,“好行”,处理得很好,很开心

     

示例第2行,一些数据,“坏线,处理不良,不快乐

     

示例第3行,一些数据,“好行”,在此之前死亡,不快乐

我正在尝试做类似的事情:

.*,"[^(",)]*[\r\n]

这个想法是在行结束之前找到一行后面跟着“没有实例”的任何内容。

序列的否定不起作用。怎么样这样呢?

注意:

由于人们一直建议基本上检查偶数双引号,因此值得注意的是,单个双引号csv条目可能包含独立双引号(例如......,“Measurement:1'2”“)。 ..)。

5 个答案:

答案 0 :(得分:1)

您可以使用:

int count = str.length() - str.replaceAll("\\"","").length();

if (count % 2 == 0) {
    // do what you want
}

答案 1 :(得分:1)

根据您当前的要求(包括您对"Measurement: 1' 2""的关注,这将选择错误的行:

^.*(?:^|,)[^",]*"(?:[^",]*(?:"[^",]*")?)+(?:$|,.*)
  1. 字符串顶部的^个锚点
  2. .*(?:^|,)会占用字符串顶部的任何字符或逗号
  3. 我们匹配“......
  4. 并且,[^",]*(?:"[^",]*")?一次或多次匹配既不是“或逗号”的字符,也可以匹配一组均衡的引号:"[^",]*"
  5. 我们要么匹配字符串的结尾,要么匹配逗号和后面的任何内容
  6. 有关转义双引号的说明

    您的输入中可能包含带有转义双引号的双引号字符串,如下所示:"abc\"de"如果是这样,我们需要将双引号字符串(?:"[^",]*")的表达式替换为更坚实的东西:(?:"(?:\\"|[^"])*")

    因此整个正则表达式将成为:

    ^.*(?:^|,)[^",]*"(?:[^",]*(?:"(?:\\"|[^"])*")?)+(?:$|,.*)
    

答案 2 :(得分:0)

这样的事情应该有效:

^[^"]*("[^"]*"[^"]*)*[^"]*$

您在整个地方看到的[^"]*意味着“任意数量的非引号字符” ("[^"]*"[^"]*)*将匹配成对的引号,而[^"]*将匹配最终引号前后的未加引号的文本。
^$锚点确保我们匹配整条线,而不仅仅是它的一部分。

基本上:如果有偶数引号,它将匹配。如果有奇数引号,则会失败。

Here's an example正则表达式在行动。


如果你正在使用的解决方案有选项,那么有一个更简单的方法不涉及正则表达式。只需计算CSV行中双引号的数量即可。如果它很奇怪,该行的引号不匹配。

答案 3 :(得分:0)

这是一个正则表达式,其他人给了我框架,最终得到了一些修改:

这将匹配任何后跟的内容,“在两者之间有或没有空格,最终没有跟随”,(也有潜在的空格),最后以换行结束。

.*,[\s]*"(?!.*"[\s]*,).*\n

答案 4 :(得分:0)

由于很多边缘情况,正则表达式实际上并不能真正可靠地工作。您应该尝试univocity-parsers,因为它是我知道的唯一可以正确处理未转义引号的CSV解析器。

它为您提供以下选项:

  • STOP_AT_CLOSING_QUOTE-如果在输入中找到未转义的引号,请累积引号字符并继续将值解析为带引号的值,直到找到结束的引号为止。

  • STOP_AT_DELIMITER-如果在输入中找到未转义的引号,则将该值视为未引用的值。这将使解析器累积所有字符,直到在输入中找到定界符或行尾为止。

  • SKIP_VALUE-如果在输入中找到未转义的引号,则将解析为的内容,直到找到下一个定界符,一切都会产生null

  • RAISE_ERROR-如果在输入中找到未转义的引号,则会引发异常

像这样使用它:

CsvParserSettings settings = new CsvParserSettings();                   
settings.setUnescapedQuoteHandling(UnescapedQuoteHandling.STOP_AT_DELIMITER);

CsvParser parser = new CsvParser(settings);
for(String row[] : parser.iterate(input)){
    System.out.println(Arrays.toString(row));
}

希望有帮助。默认情况下,它以STOP_AT_DELIMITER设置运行。

免责声明:我是这个图书馆的作者。它是开源且免费的(Apache 2.0许可证)