Ошибка «Regular Expression is too large» в PHP

Я работаю над относительно сложным и очень большим регулярным выражением. В настоящее время он составляет 41 127 символов и может несколько увеличиться по мере добавления дополнительных случаев. Я начинаю получать эту ошибку в PHP:

preg_match_all (): Ошибка компиляции: регулярное выражение слишком велико при смещении 41123

Есть ли способ увеличить размер? Следующие настройки, рекомендованные в других местах, НЕ работали, потому что они относятся к размеру данных и NOT размер регулярного выражения:

ini_set("pcre.backtrack_limit", "100000000"); ini_set("pcre.recursion_limit", "100000000"); 

Альтернативно, существует ли способ определить «переменную подматрицы» в регулярном выражении, которая может повторяться в разных местах регулярного выражения? (Я не говорю о повторении, используя * или + , или даже повторяя соответствие «1»)? Я фактически использую переменные PHP, содержащие подматрицы, которые повторяются в нескольких местах в регулярном выражении, но это приводит к расширению регулярного выражения до того, как оно передается в функции PRCE.

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

Я бы предпочел не разбивать это на подвыражения в | и пытается сопоставить подвыражения отдельно, потому что уменьшение размера будет скромным (всего 2 или 3 уровня верхнего уровня), что осложнит дальнейшее развитие.

Я не согласен с комментариями, что может быть лучший способ сделать это, но я отвечу на этот вопрос.

Вы можете увеличить максимальный размер регулярного выражения, но только путем перекомпиляции PHP самостоятельно. Из-за этого ваш код совсем не переносится, и если вы используете предварительно скомпилированные двоичные файлы, вам не повезло.

Тем не менее, я бы предложил найти альтернативу для сопоставления.

См. Pcre_internal.h для комментариев.

PCRE сохраняет смещения в сводном коде в виде 2-байтовых величин (всегда хранящихся в ординарном порядке) по умолчанию. Они используются, например, для привязки с начала подшаблона к его альтернативам и его концу. Использование 2 байтов на смещение ограничивает размер скомпилированного регулярного выражения примерно до 64 КБ, что достаточно для почти всех. Тем не менее, я получил запрос на еще больший предел. По этой причине, а также для упрощения обслуживания кода сохранение и загрузка смещений из строки байтов теперь обрабатываются макросами, которые определены здесь.

Макросы управляются значением LINK_SIZE. Это значение по умолчанию равно 2 в файле config.h, но может быть переопределено с помощью -D в командной строке. Это автоматизировано в Unix-системах с помощью команды «configure».

Таким образом, вы можете либо отредактировать ext/pcre/pcrelib/config.h из исходного источника PHP, чтобы увеличить ограничение по размеру, либо указать его при компиляции ./configure -DLINK_SIZE=4

EDIT: если вы пытаетесь совместить / разбирать HTML, я бы рекомендовал использовать DOMDocument для анализа HTML-кода, а затем пройти дерево DOM или создать XPATH, чтобы найти то, что вы ищете.

В зависимости от приложения действительными решениями являются:

  • Сократите регулярное выражение , используя DEFINE для любых избыточных выражений (см. Ниже).
  • Увеличьте максимальное ограничение на размер регулярного выражения , повторно скомпилировав PHP (см. Отличный ответ drew010). Хотя это может быть недоступно во всех средах или может возникнуть проблема совместимости при смене серверов.
  • Разделите свое регулярное выражение на | и обрабатывать полученные подвыражения отдельно. Если регулярное выражение представляет собой по существу множество ключевых слов, разделенных символом | , то преобразование в strtok или цикл с strpos может быть лучшим и быстрым выбором.
  • Используйте другой язык / механизм регулярных выражений, такой как C ++ / Boost , хотя я этого не проверял.

Решение моей конкретной проблемы: согласно комментарию Марио, используя конструкцию (?(DEFINE)...) для некоторых подвыражений, которые были повторно использованы несколько раз, уменьшил размер моего регулярного выражения с 41 127 символов до «всего» 4,071 , и это было изящное решение, чтобы избавиться от ошибки «Регулярное выражение слишком велико».

См.: (? (DEFINE) …) ссылка на синтаксис rexegg.com