Почему следующий segfault и как я могу его предотвратить?
<?php $str = ' <fieldset> <label for="go-to">Go to: </label> ' . str_repeat(' ', 10000) . '<input type="submit" value="Go" /> </fieldset> </form>'; preg_match_all("@ </?(?![bisa]\b)(?!em\b)[^>]*> # starting tag, must not be one of several inline tags (?:[^<]|</?(?:(?:[bisau]|em|strong|sup)\b)[^>]*>)* #allow text and some inline tags [\?\!\.]+ @ix", $str, $matches); ?>
Я считаю, что это вызывает … ожидание … переполнение стека.
РЕДАКТИРОВАТЬ:
Вышеприведенная версия представляет собой упрощенную версию шаблона, демонстрирующего проблему. Более полная версия:
@ </?(?![bisa]\b)(?!em\b)[^>]*> # starting tag, must not be one of several inline tags (?:[^<]|</?(?:(?:[bisau]|em|strong|sup)\b)[^>]*>)* # continue, allow text content and some inline tags # normal sentence ending [\?\!\.]+ # valid ending characters -- note elipses allowed (?<!\b[ap]m\.)(?<!\b[ap]\.m\.)(?<!digg this\!)(?<!Stumble This\!) # disallow some false positives that we don't care about \s* (?:'|&\#0*34;|'|‘)?\s* # closing single quotes, in the unusual case like "he said: 'go away'". (?:"|"|&\#0*34;|&\#x0*22;|”|&\#0*8221;|&\#x0*201D;|''|``|\xe2\x80\x9d|&\#0*148;|&\#x0*94;|\x94|\))?\s* # followed by any kind of close-quote char (?=\<) # should be followed by a tag. @ix
Цель состоит в том, чтобы найти html-блоки, которые, кажется, заканчиваются на том, что выглядит как окончательное английское предложение. Я обнаружил, что этот метод очень хорошо говорит о различии между текстом «контент» (например, телом статьи) и текстом «layout» (т. Е. Как навигационные элементы). Однако, если между ярлыками, которые он взрывает, есть огромное количество пробелов.
Первое, что я постараюсь сделать, – сделать все кванторы собственниками и все группы атомарными:
"@</?+(?![bisa]\b)(?!em\b)[^>]*+> (?>[^<]++|</?+(?>(?>[bisau]|em|strong|sup)\b)[^>]*+>)*+ [?!.]+ @ix"
Я думаю, что Джереми прав: это не откат, который убивает вас, это все сведения о состоянии, которые двигатель регулярных выражений должен сохранить, чтобы сделать возможным откат. Регулярное выражение, похоже, построено таким образом, что если ему когда-либо понадобится отступить, он все равно потерпит неудачу. Поэтому используйте притяжательные кванторы и атомные группы и не беспокойтесь, сохраняя всю эту бесполезную информацию.
РЕДАКТИРОВАТЬ: чтобы разрешить пунктуацию, заканчивающуюся предложением, вы могли бы добавить еще одну альтернативу второй строке:
(?>[^<?!.]++|(?![^?!.\s<]++<)[?!.]++|</?+(?>(?>[bisau]|em|strong|sup)\b)[^>]*+>)*+
Добавление соответствует одному или нескольким указанным символам, если они не являются последними символами без пробелов в элементе.
Я уверен, что еще более новые версии PHP связаны с PCRE 7.0, который имеет проблемы с сегментами. Я не думаю, что есть какие-то намерения по исправлению проблемы, поскольку это технически проблема PCRE, а не проблема с PHP.
Если вы скажете нам, что вы пытаетесь сделать, вы должны попытаться написать альтернативное выражение.
Исправлена ошибка: http://bugs.php.net/bug.php?id=40909
Это все еще делает то, что вы хотите?
</?(?![bisa]\b)(?!em\b)[^>]*> # starting tag, must not be one of several inline tags (?:(?>[^<\?\!\.]*)|</?(?:(?:[bisau]|em|strong|sup)\b)[^>]*>)* #allow text and some inline tags [\?\!\.]+
Ваше регулярное выражение вызывает огромное количество обратного отслеживания. С посещением 10000 персонажей он становится довольно грязным и медленным. Тем не менее, я бы не ожидал, что он рухнет …!