Аналогично Алану Муру, использует только \ 1 и не относится к группе захвата до того, как ее увидят:
#!/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";
}
Мы сопоставляем любое количество блоков (внешний (? :)), где каждый блок должен состоять из «точно одного символа из нашего предпочтительного набора, за которым не следует строка, содержащая этот символ».
Если строка может содержать символы новой строки или другие забавные вещи, возможно, придется поиграть с некоторыми флагами, чтобы сделать ^, $ и. ведите себя так, как задумано, но все зависит от конкретного вкуса RE.
Просто для глупости можно использовать положительное упреждающее утверждение для эффективного И двух регулярных выражений, поэтому мы можем проверить любую перестановку abc, утверждая, что приведенные выше совпадения, за которыми следует обычная проверка на ', состоят из N символов и состоит из следующих символов:
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";
}