Я думаю, что это будет работать еще лучше:
/(?=.*[A-Z])(?=.*[!@#\$%])/
Осмотр не потребляет символы, поэтому начало второго просмотра такое же, как и для первого.Что делает проверки для этих двух символов независимыми друг от друга.Вы можете поменять их местами, и полученное регулярное выражение все равно будет эквивалентно этому.
Следующее регулярное выражение (предложенное Гамбо) немного более эффективно, поскольку позволяет избежать ненужного возврата:
/(?=[^A-Z]*[A-Z])(?=[^!@#\$%]*[!@#\$%])/
Вкл.пароли обычной длины, однако разница во времени, вероятно, не будет легко измерима.