2013-06-26 5 views
3

Я использую Oracle 11g. Следующий оператор занимает около 3 секунд, чтобы выполнить:Regex зависает в Oracle 11g

select case when regexp_like(
    '[email protected]', 
    '^[\-a-zA-Z0-9_''^&\+\?\:]+(\.?[\-a-zA-Z0-9_''^&\+\?\:]+)*@([a-zA-Z0-9]+\.)+[a-zA-Z]{2,3}$') 
    then 'true' else 'false' end 

Добавление другого персонажа по электронному адресу:

'[email protected]' 

занимает 6 секунд. Другой персонаж 12, затем 24, 48 и т. Д. Таким образом:

'[email protected]' 

занимает около 96 секунд для запуска.

Однако удалить дефис:

'[email protected]' 

и он работает мгновенно.

Кто-нибудь знает, что здесь происходит?

+1

Независимо от проблемы производительности, вы, кажется, есть две опечаток есть: первые два класса символов содержат 'Az 'вместо' AZ'. Это включает в себя шесть символов '[\]^_ \' 'в шаблоне (поскольку их кодовые точки лежат между строчными и строчными буквами). Кроме того, нет необходимости в каких-либо экранах классов символов. –

+1

Есть действительно хорошая [статья] (http://www.regular-expressions.info/email.html) для сопоставления адресов электронной почты; начать там. Не изобретайте велосипед. –

ответ

6

Ваше регулярное выражение вызывает catastrophic backtracking.

Вкратце, ваше регулярное выражение имеет термины, которые могут и фиксируют ту же часть ввода, но не могут этого сделать. Механизм регулярных выражений должен попробовать все комбинации перед сбоем и из-за созданного дерева соответствия, каждый дополнительный символ удваивает количество способов совпадения. Создание и перемещение этого дерева приводит к геометрически экспоненциальному времени выполнения, пропорциональному 2^n - которое вы видите.

Вы можете обнаружить, что изменение двойственного выражения притяжательного квантора (т.е. ++, а не +) останавливает это поведение, потому что с ++ когда персонажи будут истощены, они остаться потребляются.


Кстати, это выражение

[\-a-zA-z0-9_''^&\+\?\:] 

можно переписать в виде:

[-\w''^&+?:] 

Потому что:

  • внутри класса символов (почти) все символы теряют особый regex значение
  • тира первый или последний является literakl дефисом (не диапазон)
  • \w == [a-zA-Z0-9_]
+2

В частности, частью, вызывающей катастрофическое обратное отслеживание, является '(\.? [\ - a-zA-z0-9 _ ''^& \ + \? \:] +) *'. –

+0

Отмечено как правильно, так как это произошло из-за катастрофического отступления. +1 к @ m.buettner для указания части, которая вызывала его. Изменение (\.? [\ - a-zA-z0-9 _ ''^& \ + \? \:] +) * На (\.[\ -a-zA-z0-9 _ ''^& \ + \? \:] +) * (другими словами, удаление начального вопросительного знака) решила проблему. ура – bornfromanegg