Как упоминалось urschrei, вы должны «векторизовать» чек. Быстрее проверять наличие миллиона элементов один раз (как это делается на C), чем проверять один элемент на миллион раз.
Прямой подход
[abc]{3}
будет соответствовать слишком многим результатам, поскольку он также будет соответствовать aab
. Чтобы не выполнять двойное совпадение a
, вам необходимо удалить a из следующей группы, оставив вас с a[bc]{2}
.
a[bc]{2}
будет соответствовать слишком много результатов, так как он также будет соответствовать 'abb'. Чтобы не выполнять двойное совпадение b
, вам необходимо удалить a из следующей группы, оставив вас с ab[c]{1}
или abc
для краткости.
abc
не будут соответствовать всем комбинациям, поэтому вам понадобится другая группа.
(abc)|([abc]{3})
, что снова будет соответствовать слишком много комбинаций.
Этот путь ведет вас вниз по пути перечисления всех перестановок в явном виде в группах.
Можете ли вы создать комбинации, чтобы вам не нужно было записывать все комбинации?
(abc)|(acb)
можно записать как a((bc)|(cb))
.
(bc)|(cb)
Я не могу сократить это дальше.
Совпадение слишком много и удаление ненужных
В зависимости от движка регулярных выражений вы можете выразить AND
в качестве заглядывания вперед, чтобы вы могли удалять совпадения. ЭТО, а не ЭТО потребляет ЭТО.
(?=[abc]{3})(?=(?!a.a))[abc]{3}
не будет соответствовать ака.
Эта проблема теперь аналогична приведенной выше, где вам нужно удалить все комбинации, которые могут нарушить ваши перестановки. В этом примере это любое выражение, содержащее один и тот же символ несколько раз.
'(.) \ 1+' в этом выражении групповые ссылки используются для собственных совпадений с одним и тем же символом несколько раз, но требуется знание, сколько групп существует в выражении, и оно очень хрупкое. Добавление групп убивает выражение ((.)\1+)
, больше не совпадает , Относительные обратные ссылки существуют и требуют знания вашего конкретного движка регулярных выражений. \k<-1>
может быть то, что вы могли искать. Я предполагаю, что .net, поскольку у меня есть тестер регулярных выражений, добавленный в закладки для этого.
Перестановки, которые я хочу исключить: nn.
n.n
.nn
nnn
Итак, я создаю эти шаблоны: ((?<1>.)\k<1>.)
((?<2>.).\k<2>)
(.(?<3>.)\k<3>)
((?<4>.)\k<4>\k<4>)
[1142 ]
Собирая все это вместе, я получаю это выражение, обратите внимание, что я использовал относительные обратные ссылки в том виде, в каком они есть в .net - ваш пробег может отличаться.
(?=[abc]{3})(?=(?!((?<1>.)\k<1>.)))(?=(?!((?<2>.).\k<2>)))(?=(?!(.(?<3>.)\k<3>)))(?=(?!((?<4>.)\k<4>\k<4>)))[abc]{3}
Ответ "да" для конкретной длины.