匹配xa?b?c的正则表达式?但不是单独的x

So8*_*res 11 regex

我正在尝试写一个匹配xa?b?c的正则表达式?但不是x.实际上,'x','a','b'和'c'不是单个字符,它们是中等复杂的子表达式,所以我试图避免像x这样的东西(abc | ab | ac | bc | A | b | C).是否有一种简单的方法可以在正则表达式中匹配"a,b和c中的至少一个,按顺序",还是我运气不好?

tch*_*ist 11

这是最短的版本:

(a)?(b)?(c)?(?(1)|(?(2)|(?(3)|(*FAIL))))
Run Code Online (Sandbox Code Playgroud)

如果你需要在一个单独的组中保持匹配,请写下:

((a)?(b)?(c)?)(?(2)|(?(3)|(?(4)|(*FAIL))))
Run Code Online (Sandbox Code Playgroud)

但是,这是不是在情况非常稳健a,bc含有捕捉组.所以写下这个:

(?<A>a)?(?<B>b)?(?<C>c)?(?(<A>)|(?(<B>)|(?(<C>)|(*FAIL))))
Run Code Online (Sandbox Code Playgroud)

如果你需要整个比赛的小组,那么写下:

(?<M>(?<A>a)?(?<B>b)?(?<C>c)?(?(<A>)|(?(<B>)|(?(<C>)|(*FAIL)))))
Run Code Online (Sandbox Code Playgroud)

如果像我一样你更喜欢多字母标识符,并且认为这种事情在没有/x模式的情况下是疯狂的,请写下:

(?x)
(?<Whole_Match>
    (?<Group_A> a) ?
    (?<Group_B> b) ?  
    (?<Group_C> c) ?

    (?(<Group_A>)           # Succeed 
      | (?(<Group_B>)       # Succeed
          | (?(<Group_C>)   # Succeed
              |             (*FAIL)
            )
        )
    )
 )
Run Code Online (Sandbox Code Playgroud)

以下是完整的测试程序,以证明所有工作:

#!/usr/bin/perl
use 5.010_000;

my @pats = (
    qr/(a)?(b)?(c)?(?(1)|(?(2)|(?(3)|(*FAIL))))/,
    qr/((a)?(b)?(c)?)(?(2)|(?(3)|(?(4)|(*FAIL))))/,
    qr/(?<A>a)?(?<B>b)?(?<C>c)?(?(<A>)|(?(<B>)|(?(<C>)|(*FAIL))))/,
    qr/(?<M>(?<A>a)?(?<B>b)?(?<C>c)?(?(<A>)|(?(<B>)|(?(<C>)|(*FAIL)))))/,
    qr{
        (?<Whole_Match>

            (?<Group_A> a) ?
            (?<Group_B> b) ?
            (?<Group_C> c) ?

            (?(<Group_A>)               # Succeed
              | (?(<Group_B>)           # Succeed
                  | (?(<Group_C>)       # Succeed
                      |                 (*FAIL)
                    )
                )
            )

        )
    }x,
);

for my $pat (@pats) {
    say "\nTESTING $pat";
    $_ = "i can match bad crabcatchers from 34 bc and call a cab";
    while (/$pat/g) {
        say "$`<$&>$'";
    }
}
Run Code Online (Sandbox Code Playgroud)

所有五个版本都会生成此输出:

i <c>an match bad crabcatchers from 34 bc and call a cab
i c<a>n match bad crabcatchers from 34 bc and call a cab
i can m<a>tch bad crabcatchers from 34 bc and call a cab
i can mat<c>h bad crabcatchers from 34 bc and call a cab
i can match <b>ad crabcatchers from 34 bc and call a cab
i can match b<a>d crabcatchers from 34 bc and call a cab
i can match bad <c>rabcatchers from 34 bc and call a cab
i can match bad cr<abc>atchers from 34 bc and call a cab
i can match bad crabc<a>tchers from 34 bc and call a cab
i can match bad crabcat<c>hers from 34 bc and call a cab
i can match bad crabcatchers from 34 <bc> and call a cab
i can match bad crabcatchers from 34 bc <a>nd call a cab
i can match bad crabcatchers from 34 bc and <c>all a cab
i can match bad crabcatchers from 34 bc and c<a>ll a cab
i can match bad crabcatchers from 34 bc and call <a> cab
i can match bad crabcatchers from 34 bc and call a <c>ab
i can match bad crabcatchers from 34 bc and call a c<ab>
Run Code Online (Sandbox Code Playgroud)

甜,嗯?

编辑:对于x在开始部分,只需x在匹配开始时放置任何你想要的东西,在该部件的第一个可选捕获组之前a,如下所示:

x(a)?(b)?(c)?(?(1)|(?(2)|(?(3)|(*FAIL))))
Run Code Online (Sandbox Code Playgroud)

或者像这样

(?x)                        # enable non-insane mode

(?<Whole_Match>
    x                       # first match some leader string

    # now match a, b, and c, in that order, and each optional
    (?<Group_A> a ) ?
    (?<Group_B> b ) ?  
    (?<Group_C> c ) ?

    # now make sure we got at least one of a, b, or c
    (?(<Group_A>)           # SUCCEED!
      | (?(<Group_B>)       # SUCCEED!
          | (?(<Group_C>)   # SUCCEED!
              |             (*FAIL)
            )
        )
    )
)
Run Code Online (Sandbox Code Playgroud)

测试句是在没有x部分的情况下构建的,所以它不会起作用,但我想我已经证明了我的意思.注意所有的x,a,b,并且c可以任意复杂的图案(是的,甚至递归),而不仅仅是单个字母,它并不重要,如果他们用自己的编号捕获组,甚至.

如果你想通过前瞻来实现这一目标,你可以这样做:

(?x)

(?(DEFINE)
       (?<Group_A> a)
       (?<Group_B> b)
       (?<Group_C> c)
)

x

(?= (?&Group_A)
  | (?&Group_B)
  | (?&Group_C)
)

(?&Group_A) ?
(?&Group_B) ?
(?&Group_C) ?
Run Code Online (Sandbox Code Playgroud)

以下是@pats在测试程序中添加到数组中的内容,以表明此方法也有效:

qr{
    (?(DEFINE)
        (?<Group_A> a)
        (?<Group_B> b)
        (?<Group_C> c)
    )

    (?= (?&Group_A)
      | (?&Group_B)
      | (?&Group_C)
    )

    (?&Group_A) ?
    (?&Group_B) ?
    (?&Group_C) ?
}x
Run Code Online (Sandbox Code Playgroud)

你会发现,请我还从来没有管理的重复任何的a,b或者c,甚至超前的技术.

我赢吗?☺

  • @Alan Moore:那么我们应该禁止没有其他标签的`regex`吗?这似乎是错误的,因为没有标签应该*不能独立.然而,你所说的听起来好像我们根本无法回答任何事情,因为我们甚至不知道简单的事情,比如BRE和ERE方言.为什么人们不应该给它最好的拍摄?如果他们没有指定,我会每次都给出一个Perl解决方案.我想我已经明确表示我也提供了Perl代码. (2认同)
  • 不,你只需要在很多时候做出最好的猜测.没有任何其他线索,我认为可以安全地假设具有最常见功能的Perl衍生品味道,例如前瞻和不情愿的量词(例如,JavaScript).如果解决方案需要更多深奥的功能(就像这个那样),我会尝试从OP中获取更多信息,建议使用非正则表达式替代方案,或者清楚地说明解决方案可以使用哪种风格.但我绝对*不要我不想阻止你发布像这样的答案 - 这很棒! (2认同)

Ign*_*ams 5

如果你没有前瞻,那就不简单了.

x(ab?c?|bc?|c)
Run Code Online (Sandbox Code Playgroud)


Tim*_*ker 5

这个怎么样:

x(?:a())?(?:b())?(?:c())?(\1|\2|\3)
Run Code Online (Sandbox Code Playgroud)

空捕获组之后a,bc将始终与(空字符串)如果 a,b还是c比赛,按照这个顺序.

(\1|\2|\3)如果前面的组中至少有一个参加了比赛,则该部分将匹配.所以如果你有x,那么正则表达式就会失败.

正则表达式的每个部分都只会被评估一次.

当然,如果x, a,b并且c是包含捕获组本身更复杂的子表达式,你必须调整相应的反向引用的数量*.

由于这个正则表达式看起来有点奇怪,这里是冗长的版本:

x          # Match x
(?:a())?   # Try to match a. If this succeeds, \1 will contain an empty string.
(?:b())?   # Same with b and \2.
(?:c())?   # Same with c and \3.
(\1|\2|\3) # Now try to match the content of one of the backreferences. 
           # This works if one of the empty parentheses participated in the match.
           # If so, the backref contains an empty string which always matches. 
           # Bingo!
Run Code Online (Sandbox Code Playgroud)

你可能需要用锚点(^$)来包围它,除非你不介意它xb在字符串中匹配cxba等.

例如,在Python中:

>>> r=re.compile(r"x(?:a())?(?:b())?(?:c())?(\1|\2|\3)$")
>>> for test in ("x", "xa", "xabc", "xba"):
...     m = r.match(test)
...     if m:
...         print("{} --> {}".format(test, m.group(0)))
...     else:
...         print("{} --> no match".format(test))
...
x --> no match
xa --> xa
xabc --> xabc
xba --> no match
Run Code Online (Sandbox Code Playgroud)

*或者,如果你的正则表达式味道知道命名的捕获组,你可以使用它们

x(?:a(?P<a>))?(?:b(?P<b>))?(?:c(?P<c>))?((?P=a)|(?P=b)|(?P=c))
Run Code Online (Sandbox Code Playgroud)

在Python/PCRE中.在.NET(以及可能的其他版本)中,拥有多个使用相同名称的捕获组甚至是合法的,这使得另一种简化成为可能:

x(?:a(?<m>))?(?:b(?<m>))?(?:c(?<m>))?\k<m>
Run Code Online (Sandbox Code Playgroud)