Кажется, что preg_match достигает предела при использовании двух совпадений

Я столкнулся с нечетной проблемой. кажется, что я достигаю своего рода предел с preg_replace, пытаясь использовать два совпадения, используя php-5.3.3

// works fine $pattern_1 = '?START(.*)STOP?'; $string = 'START' . str_repeat('x',9999999) . 'STOP' ; preg_match($pattern_1, $string , $matchedArray ) ; $pattern_2 = '?START-ONE(.*)STOP-ONE.*START-TWO(.*)STOP-TWO.*?'; // works fine $string = 'START-ONE this is head stuff STOP-ONE START-TWO' . str_repeat('x', 49970) . 'STOP-TWO' ; preg_match($pattern_2, $string , $matchedArray_2 ) ; // didnt work $string = 'START-ONE this is head stuff STOP-ONE START-TWO' . str_repeat('x', 49971) . 'STOP-TWO' ; preg_match($pattern_2, $string , $matchedArray_3 ) ; 

Первый вариант с одним совпадением использует очень большую строку и не имеет проблем.

Второй вариант имеет длину строки 50 026 и работает отлично. последний вариант имеет длину строки 50 027 (еще один), и совпадение больше не работает. поскольку число 49971 может меняться при возникновении ошибки, оно может быть изменено на нечто большее, чтобы имитировать проблему.

Любые идеи или мысли? возможно, это проблема с версией php? возможно, обходным путем является просто использовать только одно совпадение, а не два, а затем запустить preg_match в два раза?

Solutions Collecting From Web of "Кажется, что preg_match достигает предела при использовании двух совпадений"

Хорошо, PHP не очень разговорчив о ошибках регулярных выражений, он просто возвращает false для последнего случая, который просто говорит, чем ошибка, возникающая в документах PHP .

Я воспроизвел проблему, используя PCRE (механизм регулярных выражений, используемый preg_match ) в C # (но с гораздо большим количеством символов), и ошибка, которую я получаю, это PCRE_ERROR_MATCHLIMIT .

Это означает, что вы нажимаете ограничение на возврат, установленное в PCRE. Это всего лишь мера безопасности, чтобы предотвратить зависание двигателя на неопределенный срок, и я думаю, что ваша конфигурация PHP устанавливает его на низкое значение.

Чтобы устранить проблему, вы можете установить более высокое значение для параметра pcre.backtrack_limit PHP, который контролирует это ограничение:

 ini_set("pcre.backtrack_limit", "10000000"); // Actually, this is PCRE's default 

На стороне примечание:

  • Вероятно, вы должны заменить (.*) (.*?) Чтобы получить меньше бесполезного возврата и для правильности (иначе механизм регулярных выражений пройдет мимо строки STOP и ему придется вернуться к нему)
  • Использование ? как разделитель шаблонов – это плохая идея, поскольку она мешает вам использовать ? метасимвол и, следовательно, применяя вышеупомянутый совет. Действительно, вы никогда не должны использовать метасимволы регулярных выражений как разделители шаблонов.

Если вы интересуетесь более подробными сведениями на более низком уровне, вот соответствующий бит документов PCRE (акцент мой):

Поле match_limit предоставляет средства, позволяющие PCRE использовать огромное количество ресурсов при запуске шаблонов, которые не будут соответствовать, но которые имеют очень большое количество возможностей в деревьях поиска. Классическим примером является шаблон, который использует вложенные неограниченные повторы.

Внутри pcre_exec() использует функцию match() , которую он вызывает многократно (иногда рекурсивно). Предел, установленный match_limit , накладывается на количество раз, когда эта функция вызывается во время совпадения, что приводит к ограничению количества обратного отслеживания, которое может иметь место . Для шаблонов, которые не привязаны, число отсчитывается от нуля для каждой позиции в строке темы.

Когда pcre_exec() вызывается с шаблоном, который был успешно изучен с помощью опции JIT, способ выполнения сопоставления совершенно другой. Тем не менее, по-прежнему существует возможность совпадения убегания, которое продолжается очень долгое время, поэтому значение match_limit также используется в этом случае (но по-другому), чтобы ограничить продолжительность продолжения сопоставления.

Значение по умолчанию для ограничения может быть установлено при создании PCRE; значение по умолчанию – 10 миллионов , которое обрабатывает все, кроме самых экстремальных случаев. Вы можете переопределить значение по умолчанию, pcre_exec() блоком pcre_extra в котором установлен параметр match_limit , и PCRE_EXTRA_MATCH_LIMIT установлен в поле flags. Если предел превышен, pcre_exec() возвращает PCRE_ERROR_MATCHLIMIT .

Значение для предела соответствия также может быть предоставлено элементом в начале шаблона формы

  (*LIMIT_MATCH=d) 

где d – десятичное число. Однако такой параметр игнорируется, если d меньше предела, установленного вызывающим пользователем pcre_exec() или, если такой предел не установлен, меньше, чем значение по умолчанию.