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

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

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

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

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

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

我想做的事情如下:

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

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

然而,序列的否定是行不通的。 怎么样这样呢?

注意:

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

您可以使用:

 int count = str.length() - str.replaceAll("\\"","").length(); if (count % 2 == 0) { // do what you want } 

根据您当前的要求(包括您对"Measurement: 1' 2"" 1’2 "Measurement: 1' 2""的关注,这将选择不良线路:

 ^.*(?:^|,)[^",]*"(?:[^",]*(?:"[^",]*")?)+(?:$|,.*) 
  1. ^锚定在字符串的顶部
  2. .*(?:^|,)占用字符串顶部或逗号的任何字符
  3. 我们匹配“……
  4. 并且,一次或多次, [^",]*(?:"[^",]*")? 匹配既不是“或逗号”的字符,也可以是一组平衡的引号: "[^",]*"
  5. 我们要么匹配字符串的结尾,要么匹配逗号和后面的任何内容

关于转义双引号的说明

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

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

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

像这样的东西应该工作:

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

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

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

这是正则表达式的一个例子 。


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

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

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

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

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

它为您提供以下选项:

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

  • STOP_AT_DELIMITER – 如果在输入中找到未转义的引号,请将该值视为未加引号的值。 这将使解析器累积所有字符,直到在输入中找到分隔符或行结尾。

  • SKIP_VALUE – 如果在输入中找到未转义的引号,则解析内容直到找到下一个分隔符,所有内容都将生成null

  • RAISE_ERROR – 如果在输入中找到未转义的引号,则抛出exception

像这样用它:

 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许可证)