正则表达式可选捕获组?

for*_*ajt 20 regex optional capturing-group

经过几个小时的搜索,我决定问这个问题.为什么这个正则表达式:^(dog).+?(cat)?不起作用,因为我认为它应该工作(捕获第一只狗和猫,如果有的话)?我在这里错过了什么?

dog, cat
dog, dog, cat
dog, dog, dog
Run Code Online (Sandbox Code Playgroud)

das*_*ght 20

你不cat情愿地获得可选项的原因.+?是它既是可选的又是非锚定的:引擎不会强制进行匹配,因为它可以合法地将其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));
    }
}
Run Code Online (Sandbox Code Playgroud)

打印(演示1)

dog cat
dog cat
dog null
Run Code Online (Sandbox Code Playgroud)

你碰巧知道如何处理它,以防万一猫后有什么东西吗?

您可以通过构造一个匹配任何东西的棘手表达来处理它cat,如下所示:

^(dog)(?:[^c]|c[^a]|ca[^t])+(cat)?
Run Code Online (Sandbox Code Playgroud)

现在cat可能发生在没有锚点的字符串中的任何地方(演示2).

  • 谢谢.你碰巧知道如何处理它,以防万一猫后有什么东西吗?例如:`dog,dog,cat,blah`.我想只捕获第一只狗和可选的猫(最多只能有一只猫). (3认同)

Emm*_*mma 9

没有任何特定顺序,匹配此类模式的其他选项是:

方法一

对于非捕获组:

^(?:dog(?:, |$))+(?:cat)?$
Run Code Online (Sandbox Code Playgroud)

正则表达式演示 1

或者使用捕获组:

^(dog(?:, |$))+(cat)?$
Run Code Online (Sandbox Code Playgroud)

正则表达式演示 2


方法二

环顾四周,

(?<=^|, )dog|cat(?=$|,)
Run Code Online (Sandbox Code Playgroud)

正则表达式演示 3

有字界,

(?<=^|, )\b(?:dog|cat)\b(?=$|,)
Run Code Online (Sandbox Code Playgroud)

正则表达式演示 4


方法三

如果我们在字符串中只有一个cat而没有dog,那么

^(?:dog(?:, |$))*(?:cat)?$
Run Code Online (Sandbox Code Playgroud)

也会是一个选择。

正则表达式演示 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));
            }
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

输出

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
Run Code Online (Sandbox Code Playgroud)

如果你想简化/修改/探索表达式,它已经在regex101.com 的右上角面板中进行了解释。如果您愿意,您还可以在此链接中观看它如何与某些示例输入匹配。


正则表达式电路

jex.im可视化正则表达式:

在此处输入图片说明


mal*_*lef 6

@dasblinkenlight的答案很棒,但是当他/她被问到时,这是一个改进第二部分的正则表达式

你碰巧知道如何处理它,以防万一猫后有什么东西吗?

正则表达式^(dog)(.+(cat))?需要您捕获组号.3而不是2来获得可选的cat,但是在没有char-by-char技巧的情况下也能正常工作.

是演示(再次,它是从@dasblinkenlight的演示分支出来的,它允许我修补并找到这个解决方案,再次感谢!)

  • 也适用于像 ^(dog)(?:.+(cat)) 这样的非捕获组?所以你那里没有额外的捕获组 (2认同)