正则表达式可选捕获组?
Regex optional capturing group?
经过几个小时的搜索,我决定问这个问题。为什么这个正则表达式 ^(dog).+?(cat)?
不能像我认为的那样工作(即捕获第一只狗和猫,如果有的话)?我在这里错过了什么?
dog, cat
dog, dog, cat
dog, dog, dog
在 reluctantly-qualified .+?
之后没有得到可选的 cat
的原因是它既是可选的又是 non-anchored:引擎没有被强制进行匹配,因为它可以合法地将 cat
视为 .+?
序列的“尾巴”。
如果你将猫锚定在字符串的末尾,即使用 ^(dog).+?(cat)?$
,你会得到一个匹配,但是:
Pattern p = Pattern.compile("^(dog).+?(cat)?$");
for (String s : new String[] {"dog, cat", "dog, dog, cat", "dog, dog, dog"}) {
Matcher m = p.matcher(s);
if (m.find()) {
System.out.println(m.group(1)+" "+m.group(2));
}
}
这会打印 (demo 1)
dog cat
dog cat
dog null
Do you happen to know how to deal with it in case there's something after cat?
你可以通过构造一个匹配除 cat
之外的任何东西的更棘手的表达式来处理它,就像这样:
^(dog)(?:[^c]|c[^a]|ca[^t])+(cat)?
现在 cat
可以出现在字符串中没有锚点的任何位置 (demo 2)。
@dasblinkenlight 的回答很好,但是当 he/she 被问到
时,这里有一个改进第二部分的正则表达式
Do you happen to know how to deal with it in case there's something after cat?
正则表达式 ^(dog)(.+(cat))?
将要求您捕获组号。 3 而不是 2 来获得可选的猫,但在没有逐字符欺骗的情况下也能正常工作。
这里是 the demo(同样,它是从@dasblinkenlight 的演示中分叉出来的,它让我可以修改并找到这个解决方案,再次感谢!)
@figha 的扩展名可以进一步扩展,以免进行不必要的第二次捕获。
使用 ?:
使正则表达式的括号部分不可捕获。所以正则表达式变成:^(dog)(?:.+(cat))?
同样,这里是 extended demo and the regex test。
没有任何特定顺序,匹配此类模式的其他选项是:
方法一
非捕获组:
^(?:dog(?:, |$))+(?:cat)?$
RegEx Demo 1
或使用捕获组:
^(dog(?:, |$))+(cat)?$
RegEx Demo 2
方法二
环顾四周,
(?<=^|, )dog|cat(?=$|,)
RegEx Demo 3
有字边界,
(?<=^|, )\b(?:dog|cat)\b(?=$|,)
RegEx Demo 4
方法三
如果字符串中只有一个 cat
而没有 dog
,那么
^(?:dog(?:, |$))*(?:cat)?$
也是一个选择。
RegEx Demo 5
测试
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegularExpression{
public static void main(String[] args){
final String regex = "^(?:dog(?:, |$))*(?:cat)?$";
final String string = "cat\n"
+ "dog, cat\n"
+ "dog, dog, cat\n"
+ "dog, dog, dog\n"
+ "dog, dog, dog, cat\n"
+ "dog, dog, dog, dog, cat\n"
+ "dog, dog, dog, dog, dog\n"
+ "dog, dog, dog, dog, dog, cat\n"
+ "dog, dog, dog, dog, dog, dog, dog, cat\n"
+ "dog, dog, dog, dog, dog, dog, dog, dog, dog\n";
final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
final Matcher matcher = pattern.matcher(string);
while (matcher.find()) {
System.out.println("Full match: " + matcher.group(0));
for (int i = 1; i <= matcher.groupCount(); i++) {
System.out.println("Group " + i + ": " + matcher.group(i));
}
}
}
}
输出
Full match: cat
Full match: dog, cat
Full match: dog, dog, cat
Full match: dog, dog, dog
Full match: dog, dog, dog, cat
Full match: dog, dog, dog, dog, cat
Full match: dog, dog, dog, dog, dog
Full match: dog, dog, dog, dog, dog, cat
Full match: dog, dog, dog, dog, dog, dog, dog, cat
Full match: dog, dog, dog, dog, dog, dog, dog, dog, dog
如果您希望 simplify/modify/explore 表达式,regex101.com. If you'd like, you can also watch in this link 的右上面板已对其进行说明,它将如何匹配一些样本输入。
正则表达式电路
jex.im 可视化正则表达式:
经过几个小时的搜索,我决定问这个问题。为什么这个正则表达式 ^(dog).+?(cat)?
不能像我认为的那样工作(即捕获第一只狗和猫,如果有的话)?我在这里错过了什么?
dog, cat
dog, dog, cat
dog, dog, dog
在 reluctantly-qualified .+?
之后没有得到可选的 cat
的原因是它既是可选的又是 non-anchored:引擎没有被强制进行匹配,因为它可以合法地将 cat
视为 .+?
序列的“尾巴”。
如果你将猫锚定在字符串的末尾,即使用 ^(dog).+?(cat)?$
,你会得到一个匹配,但是:
Pattern p = Pattern.compile("^(dog).+?(cat)?$");
for (String s : new String[] {"dog, cat", "dog, dog, cat", "dog, dog, dog"}) {
Matcher m = p.matcher(s);
if (m.find()) {
System.out.println(m.group(1)+" "+m.group(2));
}
}
这会打印 (demo 1)
dog cat
dog cat
dog null
Do you happen to know how to deal with it in case there's something after cat?
你可以通过构造一个匹配除 cat
之外的任何东西的更棘手的表达式来处理它,就像这样:
^(dog)(?:[^c]|c[^a]|ca[^t])+(cat)?
现在 cat
可以出现在字符串中没有锚点的任何位置 (demo 2)。
@dasblinkenlight 的回答很好,但是当 he/she 被问到
时,这里有一个改进第二部分的正则表达式Do you happen to know how to deal with it in case there's something after cat?
正则表达式 ^(dog)(.+(cat))?
将要求您捕获组号。 3 而不是 2 来获得可选的猫,但在没有逐字符欺骗的情况下也能正常工作。
这里是 the demo(同样,它是从@dasblinkenlight 的演示中分叉出来的,它让我可以修改并找到这个解决方案,再次感谢!)
@figha 的扩展名可以进一步扩展,以免进行不必要的第二次捕获。
使用 ?:
使正则表达式的括号部分不可捕获。所以正则表达式变成:^(dog)(?:.+(cat))?
同样,这里是 extended demo and the regex test。
没有任何特定顺序,匹配此类模式的其他选项是:
方法一
非捕获组:
^(?:dog(?:, |$))+(?:cat)?$
RegEx Demo 1
或使用捕获组:
^(dog(?:, |$))+(cat)?$
RegEx Demo 2
方法二
环顾四周,
(?<=^|, )dog|cat(?=$|,)
RegEx Demo 3
有字边界,
(?<=^|, )\b(?:dog|cat)\b(?=$|,)
RegEx Demo 4
方法三
如果字符串中只有一个 cat
而没有 dog
,那么
^(?:dog(?:, |$))*(?:cat)?$
也是一个选择。
RegEx Demo 5
测试
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegularExpression{
public static void main(String[] args){
final String regex = "^(?:dog(?:, |$))*(?:cat)?$";
final String string = "cat\n"
+ "dog, cat\n"
+ "dog, dog, cat\n"
+ "dog, dog, dog\n"
+ "dog, dog, dog, cat\n"
+ "dog, dog, dog, dog, cat\n"
+ "dog, dog, dog, dog, dog\n"
+ "dog, dog, dog, dog, dog, cat\n"
+ "dog, dog, dog, dog, dog, dog, dog, cat\n"
+ "dog, dog, dog, dog, dog, dog, dog, dog, dog\n";
final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
final Matcher matcher = pattern.matcher(string);
while (matcher.find()) {
System.out.println("Full match: " + matcher.group(0));
for (int i = 1; i <= matcher.groupCount(); i++) {
System.out.println("Group " + i + ": " + matcher.group(i));
}
}
}
}
输出
Full match: cat
Full match: dog, cat
Full match: dog, dog, cat
Full match: dog, dog, dog
Full match: dog, dog, dog, cat
Full match: dog, dog, dog, dog, cat
Full match: dog, dog, dog, dog, dog
Full match: dog, dog, dog, dog, dog, cat
Full match: dog, dog, dog, dog, dog, dog, dog, cat
Full match: dog, dog, dog, dog, dog, dog, dog, dog, dog
如果您希望 simplify/modify/explore 表达式,regex101.com. If you'd like, you can also watch in this link 的右上面板已对其进行说明,它将如何匹配一些样本输入。
正则表达式电路
jex.im 可视化正则表达式: