Monday, September 23, 2019

php - Match a^n b^n c^n (e.g. "aaabbbccc") using regular expressions (PCRE)



It is a well known fact that modern regular expression implementations (most notably PCRE) have little in common with the original notion of regular grammars. For example you can parse the classical example of a context-free grammar {anbn; n>0} (e.g. aaabbb) using this regex (demo):



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



My question is: How far can you go? Is it also possible to parse the context-sensitive grammar {anbncn;n>0} (e.g. aaabbbccc) using PCRE?


Answer



Inspired by NullUserExceptions answer (which he already deleted as it failed for one case) I think I have found a solution myself:



$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


Try it yourself: http://codepad.viper-7.com/1erq9v







Explanation



If you consider the regex without the positive lookahead assertion (the (?=...) part), you have this:



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


This does nothing more than check that there's an arbitrary number of as, followed by an equal number of bs and cs.




This doesn't yet satisfy our grammar, because the number of as must be the same, too. We can ensure that by checking that the number of as equals the number of bs. And this is what the expression in the lookahead assertion does: (a(?-1)?b)c. The c is necessary so we don't only match a part of the bs.






Conclusion



I think this impressively shows that modern regex is not only capable of parsing non-regular grammars, but can even parse non-context-free grammars. Hopefully this will lay to rest the endless parroting of "you can't do X with regex because X isn't regular"


No comments:

Post a Comment

hard drive - Leaving bad sectors in unformatted partition?

Laptop was acting really weird, and copy and seek times were really slow, so I decided to scan the hard drive surface. I have a couple hundr...