使用正则expression式(PCRE)匹配^ nb ^ nc ^ n(例如“aaabbbccc”)

现代正则expression式的实现(最值得注意的是PCRE)与正规语法的原始概念几乎没有什么共同之处,这是众所周知的事实。 例如,你可以parsing上下文无关语法的经典例子{a n b n ; n> 0}(例如aaabbb )使用这个正则expression式( 演示 ):

 ~^(a(?1)?b)$~ 

我的问题是:你能走多远? 是否也可以使用PCRE分析上下文敏感的语法 {a n b n c n ; n> 0}(例如aaabbbccc )?

受NullUserExceptions答案(他已经删除,因为它失败了一个案例)的启发,我想我自己find了一个解决scheme:

 $regex = '~^ (?=(a(?-1)?b)c) a+(b(?-1)?c) $~x'; var_dump(preg_match($regex, 'aabbcc')); // 1 var_dump(preg_match($regex, 'aaabbbccc')); // 1 var_dump(preg_match($regex, 'aaabbbcc')); // 0 var_dump(preg_match($regex, 'aaaccc')); // 0 var_dump(preg_match($regex, 'aabcc')); // 0 var_dump(preg_match($regex, 'abbcc')); // 0 

尝试一下: http : //codepad.viper-7.com/1erq9v


说明

如果你考虑没有积极的lookahead断言( (?=...)部分)的正则expression式,你有这样的:

 ~^a+(b(?-1)?c)$~ 

这只不过是检查有a s的任意数,然后是相等数量的b s和c s。

这还不能满足我们的语法,因为a s的数量也必须是一样的。 我们可以通过检查s的个数等于b的个数来保证。 这就是前瞻断言中的expression式: (a(?-1)?b)cc是必要的,所以我们不仅匹配b的一部分。


结论

我认为这个令人印象深刻的表明,现代正则expression式不仅能够parsing非规则语法,而且甚至可以parsing非上下文无关语法。 希望这将rest无休止的“你不能用X正则expression式X,因为X不规则”

我的问题是:你能走多远?

为了不创build代码,这是一个难以理解的标点符号,我会冒险降低风险,并回答一个不同的,但非常相关的问题: 应该走多远?

正则expression式parsing器在您的工具包中是一件非常棒的事情,但它们并不是所有的事情都结束了,并且终止了所有的编程。 以可读的方式编写parsing器的能力在您的工具包中也是非常有用的。

正则expression式应该直到他们开始让你的代码难以理解。 除此之外,它们的价值至多是可疑的,最坏的情况是破坏性的。 对于这个特定的情况,而不是使用可怕的东西:

 ~^(?=(a(?-1)?b)c)a+(b(?-1)?c)$~x 

(向NikiC道歉),绝大多数人试图维护它,要么完全取代,要么耗费大量的时间阅读和理解,你可能要考虑一些非RE的东西,parsing器“解决scheme(伪代码):

 # Match "aa...abb...bcc...c" where: # - same character count for each letter; and # - character count is one or more. def matchABC (string str): # Init string index and character counts. index = 0 dim count['a'..'c'] = 0 # Process each character in turn. for ch in 'a'..'c': # Count each character in the subsequence. while index < len(str) and str[index] == ch: count[ch]++ index++ # Failure conditions. if index != len(str): return false # did not finish string. if count['a'] < 1: return false # too few a characters. if count['a'] != count['b']: return false # inequality a and b count. if count['a'] != count['c']: return false # inequality a and c count. # Otherwise, it was okay. return true 

这将在未来更容易维护。 我总是喜欢向人们build议,他们应该承担那些追随他们的人(他们必须维护他们写的代码)是精神病患者,他们知道你住在哪里 – 在我的情况下,这可能是对的,我不知道你住在哪里:-)

除非您真正需要这种正则expression式(有时候还有很好的理由,比如解释语言的性能),否则首先应该优化可读性

这是一个使用.NET regex 平衡组的替代解决scheme:

 ^(?'a'a)+(?'b-a'b)+(?(a)(?!))(?'c-b'c)+(?(b)(?!))$ 

不是PCRE,但可能是有趣的。

例如: http : //ideone.com/szhuE

编辑 :添加缺less的平衡检查组a和在线示例。

Qtax技巧

没有提到的解决scheme:

 ^(?:a(?=a*(\1?+b)b*(\2?+c)))+\1\2$ 

看看在正则expression式演示中匹配和失败。

这使用自引用组(在他的垂直正则expression式上使用的一个想法@Qtax)。