正则表达式可选捕获组?

时间:2015-02-28 14:04:50

标签: regex optional capturing-group

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

dog, cat
dog, dog, cat
dog, dog, dog

4 个答案:

答案 0 :(得分: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));
    }
}

这会打印(demo 1

dog cat
dog cat
dog null
  

你是否碰巧知道如何处理它以防猫有什么东西?

您可以通过构建一个与cat之外的任何内容匹配的棘手表达来处理它,如下所示:

^(dog)(?:[^c]|c[^a]|ca[^t])+(cat)?

现在cat可能发生在没有锚点(demo 2)的字符串中的任何位置。

答案 1 :(得分:6)

@dasblinkenlight的答案很棒,但是当他/她被问及

时,这是一个改进第二部分的正则表达式
  

你是否碰巧知道如何处理它以防猫有什么事情?

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

这里是the demo(再次,它来自@ dasblinkenlight的演示,它允许我修补并找到这个解决方案,再次感谢!)

答案 2 :(得分:4)

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

方法1

具有非捕获组:

declare @tbl table(id int,detail nvarchar(100))
insert @tbl(id,detail) values
(1,'Volvo L90H Pye No2'),(2,'Vio55-6B Pipeline Civil')

;with cte as (
select id,value,ROW_NUMBER() over(partition by id order by id) rn
from @tbl
cross apply string_split(detail,' ')
where value like '%[0-9]%'
)
select * from cte
where rn=1

RegEx Demo 1

或带有捕获组:

^(?:dog(?:, |$))+(?:cat)?$

RegEx Demo 2


方法2

具有环顾四周,

^(dog(?:, |$))+(cat)?$

RegEx Demo 3

具有单词边界,

(?<=^|, )dog|cat(?=$|,)

RegEx Demo 4


方法3

如果我们在字符串中只有一个(?<=^|, )\b(?:dog|cat)\b(?=$|,) 而没有cat,那么

dog

也将是一个选择。

RegEx Demo 5

测试

^(?:dog(?:, |$))*(?:cat)?$

输出

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));
            }
        }

    }
}

如果您希望简化/修改/探索表达式,请在regex101.com的右上角进行说明。如果愿意,您还可以在this link中查看它如何与某些示例输入匹配。


RegEx电路

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

enter image description here

答案 3 :(得分:2)

@ figha的扩展可以稍微延伸一点,不进行不必要的第二次捕获。

使用?:使正则表达式的括号部分不可捕获。所以正则表达式变成:^(dog)(?:.+(cat))?

同样,这里是extended demoregex test