3

我有一个类似apple404, orange pie, wind\,cool, sun\\mooon, earth,Java 的 CSV 字符串。准确地说,csv字符串的每个值都可以是任何东西,只要逗号和反斜杠使用反斜杠进行转义。

我需要一个正则表达式来查找前五个值。经过一番凝视后,我想出了以下内容。但它不允许在值中使用转义逗号。

Pattern pattern = Pattern.compile("([^,]+,){0,5}");
Matcher matcher = pattern.matcher("apple404, orange pie, wind\\,cool, sun\\\\mooon, earth,");
    if (matcher.find()) {
        System.out.println(matcher.group());
    } else {
        System.out.println("No match found.");
    }

有人知道如何使它适用于值中的转义逗号吗?

4

3 回答 3

2

以下基于负后视的正则表达式将起作用:

 Pattern pattern = Pattern.compile("(?:.*?(?<!(?:(?<!\\\\)\\\\)),){0,5}");

但是,对于完整的 CSV 解析,最好使用JavaCSV 之类的专用 CSV 解析器。

于 2013-08-24T05:28:38.093 回答
1

这个正则表达式效果很好。它不仅可以正确识别反斜杠转义的逗号,还可以正确识别反斜杠转义的反斜杠。此外,它生成的匹配项不包含逗号。

/(?:\\\\|\\,|[^,])*/g

(我使用标准正则表达式表示法,理解为在 Java 字符串文字中表示此正则表达式时,您将用引号替换定界符并加倍所有反斜杠。)

示例输入

"apple404, 橙派, 风\, 酷, 太阳\, 月亮, 地球"

产生这个输出

  1. “苹果404”

  2. “橘子馅饼”

  3. “风\,酷”

  4. “ 太阳\\”

  5. “月亮”

请注意,“sun”之后的双反斜杠被转义,因此不会转义以下逗号。

这个正则表达式的工作方式是首先将输入原子化为最长的序列,从双反斜杠开始(将它们视为一种可能的多字节字符值替代),然后是转义逗号(第二种可能的多字节字符替代),然后通过任何非逗号值。匹配任意数量的这些原子,后跟文字逗号。

为了获得前 N 个字段,可以简单地拼接上一个答案的匹配数组或将主表达式括在附加括号中,包括一个可选的逗号以匹配字段之间的内容,将其锚定到开头字符串以防止引擎返回更多的 N 个字段组,并对其进行量化(此处 N = 5):

/^((?:\\\\|\\,|[^,])*,?){0,5}/g

再一次,我使用标准的正则表达式表示法,但在这里我还将做一个简单的练习,将其引用为 Java 字符串:

"^((?:\\\\\\\\|\\\\,|[^,])*,?){0,5}"

到目前为止,这是此页面上唯一真正回答了 OP 指定的精确要求的两个部分的解决方案,“...逗号和反斜杠使用反斜杠进行转义。” 对于输入fi\,eld1\\,field2\\,field3\\,field4\\,field5\\,field6\\,,它仅正确匹配前五个字段fi\,eld1\\,field2\\,field3\\,field4\\,field5\\,

注意:我的第一个答案做出了相同的假设,这隐含地包含在 OP 的原始代码和示例数据中,这需要在每个字段后面加上逗号。问题是,如果输入正好是 5 个或更少的字段,并且最后一个字段后面没有逗号(等效地,是一个空字段),那么最终字段将不匹配。我不喜欢这样,所以我更新了我的两个答案,这样它们就不需要逗号了。

这个答案的缺点是它遵循 OP 的假设,即逗号之间的值包含“任何内容”加上转义的逗号或转义的反斜杠(即,双引号中的字符串之间没有区别,等等,但只能识别转义的逗号和反斜杠)。我的回答符合那个想象场景的标准。但在现实世界中,有人希望能够在 CSV 字段周围使用双引号,以便在字段中包含逗号而不使用反斜杠。

所以我附和@anubhava 的话,并建议在处理 CSV 数据时应该始终使用“真正的”CSV 解析器。否则只是一个脚本小子,而不是以任何方式真正“处理” CSV 数据。

Java评估结果

于 2013-08-24T05:30:17.223 回答
1

你可以String.split()在这里使用。通过将 指定limit为前五个元素(到6的索引)将始终是 CSV 字符串中的前五列值。如果存在任何额外的列值,它们都会溢出到 index 。045

正则表达式(?<!\\\\),确保 CSV 字符串仅以逗号分隔,而,逗号前面没有\.

String[] cols = "apple404, orange pie, wind\\,cool, sun\\\\mooon, earth, " +
                "mars, venus, pluto".split("(?<!\\\\),", 6);

System.out.println(cols.length); // 6
System.out.println(Arrays.toString(cols));
// [apple404,  orange pie,  wind\,cool,  sun\\mooon,  earth,  mars, venus, pluto]

System.out.println(cols[4]); // 5th = earth 
System.out.println(cols[5]); // 6th discarded = mars, venus, pluto
于 2013-08-24T05:36:56.473 回答