【问题标题】:Regex to match only commas not in parentheses?正则表达式仅匹配不在括号中的逗号?
【发布时间】:2021-07-01 21:08:47
【问题描述】:

我有一个类似于以下内容的字符串:

12,44,foo,bar,(23,45,200),6

我想创建一个匹配逗号的正则表达式,但只匹配不在括号内的逗号(在上面的示例中,除了 23 和 45 之后的两个逗号之外的所有逗号)。我将如何做到这一点(Java 正则表达式,如果有影响的话)?

  • 可以有嵌套括号吗?可以多于一对吗?
  • 字符串可以有不匹配的括号,如 \"12,44,12)foo,bar,(23,45,200),6\" 吗?

标签: java regex


【解决方案1】:

假设不能有嵌套的括号(否则,您不能为此任务使用 Java 正则表达式,因为不支持递归匹配):

Pattern regex = Pattern.compile(
    ",         # Match a comma\n" +
    "(?!       # only if it's not followed by...\n" +
    " [^(]*    #   any number of characters except opening parens\n" +
    " \\)      #   followed by a closing parens\n" +
    ")         # End of lookahead", 
    Pattern.COMMENTS);

此正则表达式使用negative lookahead assertion 来确保下一个括号(如果有)不是右括号。只有这样,逗号才允许匹配。

【讨论】:

  • 很好地演示了Pattern.COMMENTS 的使用。这就是 stackoverflow 上所有 Regex 答案的样子。
  • @Tim 是否有任何正则表达式可用于此字符串“12,44,foo,bar,(23,45,200(10,11(23))),6"。上面的逻辑因我提到的字符串而失败。
  • @fidato:Java 正则表达式引擎不支持您需要的递归或平衡。您是否使用其他语言?
  • @TimPietzcker 我正在使用红宝石。我也在这里发布了同样的问题:stackoverflow.com/questions/48049938/using-stringsplit-method
  • 这匹配 A(BC,D(F)G。并且不代表嵌套括号。表明这种方法是失败的。并且永远无法匹配单个括号。
【解决方案2】:

保罗,重新提出这个问题,因为它有一个没有提到的简单解决方案。 (在为regex bounty quest 做一些研究时发现了你的问题。)

现有的解决方案还检查逗号后面没有括号,但这并不能保证它嵌入在括号中。

正则表达式非常简单:

\(.*?\)|(,)

交替的左侧匹配完整的括号集。我们将忽略这些匹配。右侧将逗号匹配并捕获到第 1 组,我们知道它们是正确的逗号,因为它们没有被左侧的表达式匹配。

在此demo 中,您可以在右下方窗格中看到第 1 组捕获。

您说要匹配逗号,但您可以使用相同的一般思想来拆分或替换。

要匹配逗号,您需要检查第 1 组。这个完整程序的唯一目标就是做到这一点。

import java.util.*;
import java.io.*;
import java.util.regex.*;
import java.util.List;

class Program {
public static void main (String[] args) throws java.lang.Exception  {

String subject = "12,44,foo,bar,(23,45,200),6";
Pattern regex = Pattern.compile("\\(.*?\\)|(,)");
Matcher regexMatcher = regex.matcher(subject);
List<String> group1Caps = new ArrayList<String>();

// put Group 1 captures in a list
while (regexMatcher.find()) {
if(regexMatcher.group(1) != null) {
group1Caps.add(regexMatcher.group(1));
}
} // end of building the list

// What are all the matches?
System.out.println("\n" + "*** Matches ***");
if(group1Caps.size()>0) {
for (String match : group1Caps) System.out.println(match);
}
} // end main
} // end Program

这是live demo

要使用相同的技术进行拆分或替换,请参阅参考文章中的代码示例。

参考

  1. How to match pattern except in situations s1, s2, s3
  2. How to match a pattern unless...

【讨论】:

  • 出于某种原因,这在regexr.com 中不起作用
【解决方案3】:

我不理解这种对正则表达式的痴迷,因为它们不适合它们所用于的大多数任务。

String beforeParen = longString.substring(longString.indexOf('(')) + longString.substring(longString.indexOf(')') + 1);
int firstComma = beforeParen.indexOf(',');
while (firstComma != -1) {
    /* do something. */
    firstComma = beforeParen.indexOf(',', firstComma + 1);
}

(当然这假设总是有一个左括号和一个匹配的右括号在它之后的某个时候出现。)

【讨论】:

  • 它假定括号后没有逗号。你测试过这个吗?它甚至在 Paul 提供的示例字符串上失败。编写一个不会因格式错误的输入而阻塞的正确解析器可能与编写正确的正则表达式一样难(如果不是更难的话)。我会大大地如果输入符合定义的标准,则在此用例中首选正则表达式。
  • 你是对的,我忽略了右括号后面的部分。固定的。 :)
  • 您如何处理1,2,(3,4),5,6,(7,8) 之类的输入?
  • 抱歉,除非问题的说明变得更详细,否则我拒绝与您的 let-me-break-your-parser 游戏一起玩。 :)
  • 如果 OP 的场景不是应该使用正则表达式,那么我不确定它是什么应该用于。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-03
  • 2021-11-16
  • 2021-07-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多