在 Java 中使用 RegEx,如何捕获由双竖线分隔的组,不包括双引号括起来的组?
Using RegEx in Java, how do I capture groups delimited by double pipes excluding those enclosed by double quotes?
示例:
abc | efg || $something("arg 1", "arg 2||(a|b)") || 123
或没有空格
abc|efg||$something("arg 1", "arg 2||(a|b)")||123
需要什么 RegEx 模式才能得到以下组:
abc | efg
$something("arg 1", "arg 2||(a|b)")
123
共3组。
另一个例子:
"abc || efg" || 123
应该给我2组
"abc || efg"
123
基本上它通过双管道切割或拆分字符串,但不包括双引号内的双管道。
我失败的尝试如下:
.+?(?=\|\|)|.*
\".+?\"|.+?(?=\|\|)|.*
如果可以接受不使用拆分而是通过多个匹配,则可以使用
(?<=\ \|\|\ |^)([^\"]+?(?:\"[^\"]*\")?)+?(?=\ \|\|\ |$)
解释:
- 向后看:“||”或行首?
- 一些非引用文字,越少越好
- 可选的,用引号括起来的非引号块
- 2.-3。至少重复一次
- 先行:“||”或行尾?
匹配将恰好是用“||”和引号 || 拆分的结果忽略。
这就是我要做的,正则表达式方面的:
(?:^|\|\|)(?:(?!\|\|)(?!").|"(?:[^"\]|\.)*")*
Regex101 演示 here。你可以看到右边的匹配项,我把它们放在捕获组中以省略 ||
,你可以在 Java 中使用 m.group(1)
来获取它们。 Java 不是我的强项,但应该是这样的:
String s ="abc | efg || $something(\"arg 1\", \"arg 2||(a|b)\") || 123";
String patternStr="(?:^|\|\|)(?:(?!\|\|)(?!\").|\"(?:[^\"\\]|\\.)*\")*";
Pattern p = Pattern.compile(patternStr);
Matcher m = p.matcher(s);
while (m.find()){
System.out.println(m.group(1));
}
编辑: 意识到回头看你可能想要接受 "$something("arg with \" in it", "arg 2||(a|b)"
所以更新正则表达式来做到这一点。
添加: 结合 Bohemian 的解决方案,如果更简单,您可以拆分:
\|\|(?=(?:(?:(?:[^"\]|\.)*"){2})*[^"]*$)
Regex101 或 Java:
String[] parts = str.split("\|\|(?=(?:(?:(?:[^\"\\]|\\.)*\"){2})*[^\"]*$)");
\|\|(?=(?:[^"]*"[^"]*")*[^"]*$)
被 this.See 演示拆分。
在双管道上拆分,但只有那些后跟 偶数 个引号的管道:
String[] parts = str.split("\|\|(?=(([^\"]*\"){2})*[^\"]*$");
使用这个简短的正则表达式 \|\|(?!\([^\)]+\))
它可能有效。
示例:
abc | efg || $something("arg 1", "arg 2||(a|b)") || 123
或没有空格
abc|efg||$something("arg 1", "arg 2||(a|b)")||123
需要什么 RegEx 模式才能得到以下组:
abc | efg
$something("arg 1", "arg 2||(a|b)")
123
共3组。
另一个例子:
"abc || efg" || 123
应该给我2组
"abc || efg"
123
基本上它通过双管道切割或拆分字符串,但不包括双引号内的双管道。
我失败的尝试如下:
.+?(?=\|\|)|.*
\".+?\"|.+?(?=\|\|)|.*
如果可以接受不使用拆分而是通过多个匹配,则可以使用
(?<=\ \|\|\ |^)([^\"]+?(?:\"[^\"]*\")?)+?(?=\ \|\|\ |$)
解释:
- 向后看:“||”或行首?
- 一些非引用文字,越少越好
- 可选的,用引号括起来的非引号块
- 2.-3。至少重复一次
- 先行:“||”或行尾?
匹配将恰好是用“||”和引号 || 拆分的结果忽略。
这就是我要做的,正则表达式方面的:
(?:^|\|\|)(?:(?!\|\|)(?!").|"(?:[^"\]|\.)*")*
Regex101 演示 here。你可以看到右边的匹配项,我把它们放在捕获组中以省略 ||
,你可以在 Java 中使用 m.group(1)
来获取它们。 Java 不是我的强项,但应该是这样的:
String s ="abc | efg || $something(\"arg 1\", \"arg 2||(a|b)\") || 123";
String patternStr="(?:^|\|\|)(?:(?!\|\|)(?!\").|\"(?:[^\"\\]|\\.)*\")*";
Pattern p = Pattern.compile(patternStr);
Matcher m = p.matcher(s);
while (m.find()){
System.out.println(m.group(1));
}
编辑: 意识到回头看你可能想要接受 "$something("arg with \" in it", "arg 2||(a|b)"
所以更新正则表达式来做到这一点。
添加: 结合 Bohemian 的解决方案,如果更简单,您可以拆分:
\|\|(?=(?:(?:(?:[^"\]|\.)*"){2})*[^"]*$)
Regex101 或 Java:
String[] parts = str.split("\|\|(?=(?:(?:(?:[^\"\\]|\\.)*\"){2})*[^\"]*$)");
\|\|(?=(?:[^"]*"[^"]*")*[^"]*$)
被 this.See 演示拆分。
在双管道上拆分,但只有那些后跟 偶数 个引号的管道:
String[] parts = str.split("\|\|(?=(([^\"]*\"){2})*[^\"]*$");
使用这个简短的正则表达式 \|\|(?!\([^\)]+\))
它可能有效。