优化这个可怕的正则表达式

时间:2012-01-25 04:52:22

标签: regex optimization

这个想法是在一个任意长度的字符串中只允许四个'a'实例和两个'b'实例。

现在,其他角色并不重要,我关心的是四个'a'和两个'b'。我想出的就是:

m{
  ^[^ab]*
  (
    (b[^ab]*b[^ab]*a[^ab]*a[^ab]*a[^ab]*a)|
    (b[^ab]*a[^ab]*b[^ab]*a[^ab]*a[^ab]*a)|
    (b[^ab]*a[^ab]*a[^ab]*b[^ab]*a[^ab]*a)|
    (b[^ab]*a[^ab]*a[^ab]*a[^ab]*b[^ab]*a)|
    (b[^ab]*a[^ab]*a[^ab]*a[^ab]*a[^ab]*b)|
    (a[^ab]*b[^ab]*b[^ab]*a[^ab]*a[^ab]*a)|
    (a[^ab]*b[^ab]*a[^ab]*b[^ab]*a[^ab]*a)|
    (a[^ab]*b[^ab]*a[^ab]*a[^ab]*b[^ab]*a)|
    (a[^ab]*b[^ab]*a[^ab]*a[^ab]*a[^ab]*b)|
    (a[^ab]*a[^ab]*b[^ab]*b[^ab]*a[^ab]*a)|
    (a[^ab]*a[^ab]*b[^ab]*a[^ab]*b[^ab]*a)|
    (a[^ab]*a[^ab]*b[^ab]*a[^ab]*a[^ab]*b)|
    (a[^ab]*a[^ab]*a[^ab]*b[^ab]*b[^ab]*a)|
    (a[^ab]*a[^ab]*a[^ab]*b[^ab]*a[^ab]*b)|
    (a[^ab]*a[^ab]*a[^ab]*a[^ab]*b[^ab]*b)
  )
  [^ab]*$
}x;

(一如既往,这是Perl正则表达式)

除了仅使用附加括号重新组合案例之外,还有更好的解决方案吗?在正则表达式中,对已接受的案例进行置换似乎有点“错误”。

这个问题是在不同的借口下在stackoverflow上提出的。那个问题当时被删除了,因为写得不好,没有尝试解决问题,而且很明显,这是TCS课程的作业。无论如何,我尝试回答这个问题,并提出了一条消息,该问题已被删除(同时)。无论如何,手头的问题对我来说似乎很有意思,所以我决定再问一遍,但是有更好的借口。)

3 个答案:

答案 0 :(得分:5)

四个a要求:

[^a]*(?:a[^a]*){4}

两个b要求:

[^b]*(?:b[^b]*){2}

通过在先行中封装第一个要求来组合:

^(?=[^a]*(?:a[^a]*){4}$)[^b]*(?:b[^b]*){2}$

答案 1 :(得分:2)

更好的解决方案是(伪代码):

def hasFourAsAndTwoBs (s):
    numAs = 0
    numBs = 0

    for each ch in s:
        if ch == 'a':
            if numAs == 4:
                return false
            numAs = numAs + 1
        if ch == 'b':
            if numBs == 2:
                return false
            numBs = numBs + 1

    # Get rid of this if it's "up to" 4 as and 2 bs rather than "exactly".
    if numAs != 4 and numBs != 2:
        return false

    return true

换句话说,当正则表达式变得比以更易读的方式做同样事情的代码更大时,它们就不再有用了。

为作业使用正确的工具,并首先优化可读性

答案 2 :(得分:0)

$string !~ m/(?:.*?a.*?){5,}|(?:.*?b.*?){3,}/x)