#python #regex #loops #freeze
#python #регулярное выражение #циклы #заморозить
Вопрос:
Я пытаюсь сопоставить, если за ним следует одно слово s|||s
, а затем еще одно слово, за которым следует, s|||s
поэтому я использую это регулярное выражение:
single_word_regex = r'(w ) s|||s(w )s|||s.*'
И когда я попытался сопоставить эту строку, сопоставление регулярных выражений зависает или занимает минуты (возможно, переходит в какой-то «глубокий цикл»)
>>> import re
>>> import time
>>> single_word_regex = r'(w ) s|||s(w )s|||s.*'
>>> x = u'amornratchatchawansawangwong ||| amornratchatchawansawangwong . ||| 0.594819 0.5 0.594819 0.25 ||| 0-0 0-1 ||| 1 1 1 ||| |||'
>>> z = u'amor 我 ||| amor . i ||| 0.594819 0.0585231 0.594819 0.0489472 ||| 0-0 0-1 1-2 ||| 2 2 2 ||| |||'
>>> y = u'amor ||| amor ||| 0.396546 0.0833347 0.29741 0.08 ||| 0-0 0-1 ||| 3 4 2 ||| |||'
>>> re.match(single_word_regex, z, re.U)
>>> re.match(single_word_regex, y, re.U)
<_sre.SRE_Match object at 0x105b879c0>
>>> start = time.time(); re.match(single_word_regex, y, re.U); print time.time() - start
9.60826873779e-05
>>> start = time.time(); re.match(single_word_regex, x, re.U); print time.time() - start # It hangs...
Почему это занимает так много времени?
Есть ли лучшее / более простое регулярное выражение для захвата этого условия len(x.split(' ||| ')[0].split()) == 1 == len(x.split(' ||| ').split())
?
Комментарии:
1.
(w )
это зло, удалите последнее.
2. Действительно зло. Теперь он работает с
(w )
. @SebastianProske не хотите объяснить, почему?3. Ну, если
w
означает char*x , то(w )
означает char*x*y . Когда механизм регулярных выражений обрабатывает второе, может быть несколько комбинаций x и y , которые работают, поэтому он может зависнуть, пытаясь найти единственное решение. Я не знаю деталей движка, но на самом деле это не совсем корректная / четко определенная вещь для анализа.4.
(w )
захватит все символы слова,(w)
повторно захватит один символ слова. В первом случае вы получаете захват одной строки, во втором — каждый символ захватывается индивидуально как его собственная группа захвата.5. regular-expressions.info/catastrophic.html может быть полезной ссылкой, позволяющей избежать зависания регулярных выражений. tl;dr будьте осторожны с группировкой регулярных выражений, потому что она может вести себя неожиданным образом
Ответ №1:
Обратите внимание, что сам по себе r'(w ) '
шаблон не приведет к катастрофическому возврату, он будет только «злым» внутри более длинного выражения, и особенно когда он помещен рядом с началом шаблона, поскольку в случае сбоя последующих подшаблонов движок возвращается к этому, и поскольку квантификатор 1 внутри сновав количественном
выражении это создает огромное количество возможных вариантов, которые нужно попробовать перед сбоем. Вы можете взглянуть на демонстрацию регулярных выражений и щелкнуть отладчик регулярных выражений слева, чтобы увидеть пример поведения механизма регулярных выражений.
Текущее регулярное выражение может быть записано как
r'^(w )s|{3}s(w )s|{3}s(.*)'
Смотрите демонстрацию регулярных выражений, где будет совпадение, если вы удалите пробел и .
во втором поле.
Подробные сведения:
^
— начало строки (не обязательно сre.match
)(w )
— (Группа 1) 1 буквы / цифры / подчеркиванияs
— пробел|{3}
— 3 символа каналаs(w )s|{3}s
— см. Выше ((w )
создает группу 2)(.*)
— (Группа 3) любые символы 0 , отличные от символов разрыва строки.