Like Alan Moore, using only \ 1 and does not belong to the capture group before he was spotted:
#!/usr/bin/perl my $re = qr/^(?:([abc])(?!.*\1))*$/; foreach (qw(ba pabc abac a cc cba abcd abbbbc), '') { print "'$_' ", ($_ =~ $re) ? "matches" : "does not match", " \$re \n"; }
We match any number of blocks (external (? :)), where each block must consist of "exactly one character from our preferred set, which is not followed by a line containing that character".
If a string can contain newline characters or other fun things, you may need to play with some flags to make ^, $ and. behave as intended, but it all depends on the specific taste of RE.
Just for stupidity, you can effectively use the positive forward statement and two regular expressions, so we can test any permutation abc, claiming that the above matches, followed by the usual check for ', are N characters long and consists of these characters:
my $re2 = qr/^(?=$re)[abc]{3}$/; foreach (qw(ba pabc abac a cc abcd abbbbc abc acb bac bca cab cba), '') { print "'$_' ", ($_ =~ $re2) ? "matches" : "does not match", " \$re2 \n"; }
source share