Angular js Регулярное выражение в директиве валидации вызывает ошибку Error: too much recursion
У меня директива, проверяющая имя хоста с регулярным выражением: /^(xn--)?(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-_][a-zA-Z0-9])\.?)+([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-][A-Za-z0-9])*$/ когда количество символов > 25 в поле которое проверяем и дописываем любой символ, например %, браузер зависает. С буквенными символами проблем не возникает, проблемы нету также при маленьком количестве символов. Подскажите, пожалуйста что не так.
Ответы (1 шт):
Если не ошибаюсь, вы столкнулись с явлением "Катастрофический возврат". Описание и пути решения можно посмотреть тут: https://learn.javascript.ru/regexp-catastrophic-backtracking
Возможно, прочитав, вы сами найдёте другой путь оптимизации. Могу предложить второй из предложенных там путей, просто применяю его формально, глубоко не вникая в вашу ситуацию.
Чтобы регулярка была чуть менее запутанная, я сначала попробовал её сократить: добавил флаг игнорирования регистра, чтобы можно было использовать только a-z, числовой диапазон заменил на \d.
Далее я вставил знак отмены запоминания выражений в скобках ?:, чтобы было проще применять решение проблемы.
Наконец, окружил первую большую группу повторений предложенным заглядыванием вперёд: (?=(группа))\1.
Получается что-то такое:
const re = /^(?:xn--)?(?=((?:(?:[a-z\d]|[a-z\d][a-z\d_-][a-z\d])\.?)+))\1(?:[a-z\d]|[a-z\d][a-z\d-][a-z\d])*$/i;
console.log(re.test('example.example.example.example.example.example.example.example.org%'));
Ещё мне вот что пришло в голову. Поскольку у вас очень ограниченный набор разрешённых символов, а сложность только в разных допустимых их сочетаниях, вы можете помочь движку регулярок, вставив в начало проверку с заглядыванием вперёд до конца, в которой укажите разрешённые символы: /^(?=[\w.-]+$)дальше-ваша-регулярка/i. Тогда многие тупиковые варианты будут отметаться с ходу:
const re = /^(?=[\w.-]+$)(xn--)?(([a-z\d]|[a-z\d][a-z\d_-][a-z\d])\.?)+([a-z\d]|[a-z\d][a-z\d-][a-z\d])*$/i;
console.log(re.test('example.example.example.example.example.example.example.example.org%'));